[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-friends/classes/ -> class-bp-friends-friendship.php (source)

   1  <?php
   2  /**
   3   * BuddyPress Friends Classes.
   4   *
   5   * @package BuddyPress
   6   * @subpackage FriendsFriendship
   7   * @since 1.0.0
   8   */
   9  
  10  // Exit if accessed directly.
  11  defined( 'ABSPATH' ) || exit;
  12  
  13  /**
  14   * BuddyPress Friendship object.
  15   *
  16   * @since 1.0.0
  17   */
  18  class BP_Friends_Friendship {
  19  
  20      /**
  21       * ID of the friendship.
  22       *
  23       * @since 1.0.0
  24       * @var int
  25       */
  26      public $id;
  27  
  28      /**
  29       * User ID of the friendship initiator.
  30       *
  31       * @since 1.0.0
  32       * @var int
  33       */
  34      public $initiator_user_id;
  35  
  36      /**
  37       * User ID of the 'friend' - the one invited to the friendship.
  38       *
  39       * @since 1.0.0
  40       * @var int
  41       */
  42      public $friend_user_id;
  43  
  44      /**
  45       * Has the friendship been confirmed/accepted?
  46       *
  47       * @since 1.0.0
  48       * @var int
  49       */
  50      public $is_confirmed;
  51  
  52      /**
  53       * Is this a "limited" friendship?
  54       *
  55       * Not currently used by BuddyPress.
  56       *
  57       * @since 1.0.0
  58       * @var int
  59       */
  60      public $is_limited;
  61  
  62      /**
  63       * Date the friendship was created.
  64       *
  65       * @since 1.0.0
  66       * @var string
  67       */
  68      public $date_created;
  69  
  70      /**
  71       * Is this a request?
  72       *
  73       * Not currently used in BuddyPress.
  74       *
  75       * @since 1.0.0
  76       * @var bool
  77       */
  78      public $is_request;
  79  
  80      /**
  81       * Should additional friend details be queried?
  82       *
  83       * @since 1.0.0
  84       * @var bool
  85       */
  86      public $populate_friend_details;
  87  
  88      /**
  89       * Details about the friend.
  90       *
  91       * @since 1.0.0
  92       * @var BP_Core_User
  93       */
  94      public $friend;
  95  
  96      /**
  97       * Constructor method.
  98       *
  99       * @since 1.5.0
 100       * @since 10.0.0 Updated to add deprecated notice for `$is_request`.
 101       *
 102       * @param int|null $id                      Optional. The ID of an existing friendship.
 103       * @param bool     $is_request              Deprecated.
 104       * @param bool     $populate_friend_details Optional. True if friend details should be queried.
 105       */
 106  	public function __construct( $id = null, $is_request = false, $populate_friend_details = true ) {
 107  
 108          if ( false !== $is_request ) {
 109              _deprecated_argument(
 110                  __METHOD__,
 111                  '1.5.0',
 112                  sprintf(
 113                      /* translators: 1: the name of the method. 2: the name of the file. */
 114                      esc_html__( '%1$s no longer accepts $is_request. See the inline documentation at %2$s for more details.', 'buddypress' ),
 115                      __METHOD__,
 116                      __FILE__
 117                  )
 118              );
 119          }
 120  
 121          $this->is_request = $is_request;
 122  
 123          if ( ! empty( $id ) ) {
 124              $this->id                      = (int) $id;
 125              $this->populate_friend_details = $populate_friend_details;
 126              $this->populate( $this->id );
 127          }
 128      }
 129  
 130      /**
 131       * Set up data about the current friendship.
 132       *
 133       * @since 1.0.0
 134       *
 135       * @global BuddyPress $bp The one true BuddyPress instance.
 136       * @global wpdb $wpdb WordPress database object.
 137       */
 138  	public function populate() {
 139          global $wpdb;
 140  
 141          $bp = buddypress();
 142  
 143          // Check cache for friendship data.
 144          $friendship = wp_cache_get( $this->id, 'bp_friends_friendships' );
 145  
 146          // Cache missed, so query the DB.
 147          if ( false === $friendship ) {
 148              $friendship = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) );
 149  
 150              wp_cache_set( $this->id, $friendship, 'bp_friends_friendships' );
 151          }
 152  
 153          // No friendship found so set the ID and bail.
 154          if ( empty( $friendship ) || is_wp_error( $friendship ) ) {
 155              $this->id = 0;
 156              return;
 157          }
 158  
 159          $this->initiator_user_id = (int) $friendship->initiator_user_id;
 160          $this->friend_user_id    = (int) $friendship->friend_user_id;
 161          $this->is_confirmed      = (int) $friendship->is_confirmed;
 162          $this->is_limited        = (int) $friendship->is_limited;
 163          $this->date_created      = $friendship->date_created;
 164  
 165          if ( ! empty( $this->populate_friend_details ) ) {
 166              if ( bp_displayed_user_id() === $this->friend_user_id ) {
 167                  $this->friend = new BP_Core_User( $this->initiator_user_id );
 168              } else {
 169                  $this->friend = new BP_Core_User( $this->friend_user_id );
 170              }
 171          }
 172      }
 173  
 174      /**
 175       * Save the current friendship to the database.
 176       *
 177       * @since 1.0.0
 178       *
 179       * @global BuddyPress $bp The one true BuddyPress instance.
 180       * @global wpdb $wpdb WordPress database object.
 181       *
 182       * @return bool True on success, false on failure.
 183       */
 184  	public function save() {
 185          global $wpdb;
 186  
 187          $bp = buddypress();
 188  
 189          $this->initiator_user_id = apply_filters( 'friends_friendship_initiator_user_id_before_save', $this->initiator_user_id, $this->id );
 190          $this->friend_user_id    = apply_filters( 'friends_friendship_friend_user_id_before_save', $this->friend_user_id, $this->id );
 191          $this->is_confirmed      = apply_filters( 'friends_friendship_is_confirmed_before_save', $this->is_confirmed, $this->id );
 192          $this->is_limited        = apply_filters( 'friends_friendship_is_limited_before_save', $this->is_limited, $this->id );
 193          $this->date_created      = apply_filters( 'friends_friendship_date_created_before_save', $this->date_created, $this->id );
 194  
 195          /**
 196           * Fires before processing and saving the current friendship request.
 197           *
 198           * @since 1.0.0
 199           *
 200           * @param BP_Friends_Friendship $value Current friendship object. Passed by reference.
 201           */
 202          do_action_ref_array( 'friends_friendship_before_save', array( &$this ) );
 203  
 204          // Update.
 205          if ( ! empty( $this->id ) ) {
 206              $result = $wpdb->query( $wpdb->prepare( "UPDATE {$bp->friends->table_name} SET initiator_user_id = %d, friend_user_id = %d, is_confirmed = %d, is_limited = %d, date_created = %s WHERE id = %d", $this->initiator_user_id, $this->friend_user_id, $this->is_confirmed, $this->is_limited, $this->date_created, $this->id ) );
 207  
 208          // Save.
 209          } else {
 210              $result = $wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->friends->table_name} ( initiator_user_id, friend_user_id, is_confirmed, is_limited, date_created ) VALUES ( %d, %d, %d, %d, %s )", $this->initiator_user_id, $this->friend_user_id, $this->is_confirmed, $this->is_limited, $this->date_created ) );
 211              $this->id = $wpdb->insert_id;
 212          }
 213  
 214          /**
 215           * Fires after processing and saving the current friendship request.
 216           *
 217           * @since 1.0.0
 218           *
 219           * @param BP_Friends_Friendship $value Current friendship object. Passed by reference.
 220           */
 221          do_action_ref_array( 'friends_friendship_after_save', array( &$this ) );
 222  
 223          return $result;
 224      }
 225  
 226      /**
 227       * Delete the current friendship from the database.
 228       *
 229       * @since 1.0.0
 230       *
 231       * @global BuddyPress $bp The one true BuddyPress instance.
 232       * @global wpdb $wpdb WordPress database object.
 233       *
 234       * @return bool|int
 235       */
 236  	public function delete() {
 237          global $wpdb;
 238  
 239          $bp = buddypress();
 240  
 241          return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) );
 242      }
 243  
 244      /** Static Methods ********************************************************/
 245  
 246      /**
 247       * Get the friendships for a given user.
 248       *
 249       * @since 2.6.0
 250       *
 251       * @param int    $user_id  ID of the user whose friends are being retrieved.
 252       * @param array  $args     {
 253       *        Optional. Filter parameters.
 254       *        @type int    $id                ID of specific friendship to retrieve.
 255       *        @type int    $initiator_user_id ID of friendship initiator.
 256       *        @type int    $friend_user_id    ID of specific friendship to retrieve.
 257       *        @type int    $is_confirmed      Whether the friendship has been accepted.
 258       *        @type int    $is_limited        Whether the friendship is limited.
 259       *        @type string $order_by          Column name to order by.
 260       *        @type string $sort_order        ASC or DESC. Default DESC.
 261       * }
 262       * @param string $operator Optional. Operator to use in `wp_list_filter()`.
 263       *
 264       * @return array $friendships Array of friendship objects.
 265       */
 266  	public static function get_friendships( $user_id, $args = array(), $operator = 'AND' ) {
 267  
 268          if ( empty( $user_id ) ) {
 269              $user_id = bp_loggedin_user_id();
 270          }
 271  
 272          $r = bp_parse_args(
 273              $args,
 274              array(
 275                  'id'                => null,
 276                  'initiator_user_id' => null,
 277                  'friend_user_id'    => null,
 278                  'is_confirmed'      => null,
 279                  'is_limited'        => null,
 280                  'order_by'          => 'date_created',
 281                  'sort_order'        => 'DESC',
 282                  'page'              => null,
 283                  'per_page'          => null,
 284              ),
 285              'bp_get_user_friendships'
 286          );
 287  
 288          // First, we get all friendships that involve the user.
 289          $friendship_ids = wp_cache_get( $user_id, 'bp_friends_friendships_for_user' );
 290          if ( false === $friendship_ids ) {
 291              $friendship_ids = self::get_friendship_ids_for_user( $user_id );
 292              wp_cache_set( $user_id, $friendship_ids, 'bp_friends_friendships_for_user' );
 293          }
 294  
 295          // Prime the membership cache.
 296          $uncached_friendship_ids = bp_get_non_cached_ids( $friendship_ids, 'bp_friends_friendships' );
 297          if ( ! empty( $uncached_friendship_ids ) ) {
 298              $uncached_friendships = self::get_friendships_by_id( $uncached_friendship_ids );
 299  
 300              foreach ( $uncached_friendships as $uncached_friendship ) {
 301                  wp_cache_set( $uncached_friendship->id, $uncached_friendship, 'bp_friends_friendships' );
 302              }
 303          }
 304  
 305          // Assemble filter array.
 306          $filters = wp_array_slice_assoc( $r, array( 'id', 'initiator_user_id', 'friend_user_id', 'is_confirmed', 'is_limited' ) );
 307          foreach ( $filters as $filter_name => $filter_value ) {
 308              if ( is_null( $filter_value ) ) {
 309                  unset( $filters[ $filter_name ] );
 310              }
 311          }
 312  
 313          // Populate friendship array from cache, and normalize.
 314          $friendships = array();
 315          $int_keys    = array( 'id', 'initiator_user_id', 'friend_user_id' );
 316          $bool_keys   = array( 'is_confirmed', 'is_limited' );
 317          foreach ( $friendship_ids as $friendship_id ) {
 318              // Create a limited BP_Friends_Friendship object (don't fetch the user details).
 319              $friendship = new BP_Friends_Friendship( $friendship_id, false, false );
 320  
 321              // Sanity check.
 322              if ( ! isset( $friendship->id ) ) {
 323                  continue;
 324              }
 325  
 326              // Integer values.
 327              foreach ( $int_keys as $index ) {
 328                  $friendship->{$index} = intval( $friendship->{$index} );
 329              }
 330  
 331              // Boolean values.
 332              foreach ( $bool_keys as $index ) {
 333                  $friendship->{$index} = (bool) $friendship->{$index};
 334              }
 335  
 336              // We need to support the same operators as wp_list_filter().
 337              if ( 'OR' == $operator || 'NOT' == $operator ) {
 338                  $matched = 0;
 339  
 340                  foreach ( $filters as $filter_name => $filter_value ) {
 341                      if ( isset( $friendship->{$filter_name} ) && $filter_value == $friendship->{$filter_name} ) {
 342                          $matched++;
 343                      }
 344                  }
 345  
 346                  if ( ( 'OR' == $operator && $matched > 0 )
 347                    || ( 'NOT' == $operator && 0 == $matched ) ) {
 348                      $friendships[ $friendship->id ] = $friendship;
 349                  }
 350  
 351              } else {
 352                  /*
 353                   * This is the more typical 'AND' style of filter.
 354                   * If any of the filters miss, we move on.
 355                   */
 356                  foreach ( $filters as $filter_name => $filter_value ) {
 357                      if ( ! isset( $friendship->{$filter_name} ) || $filter_value != $friendship->{$filter_name} ) {
 358                          continue 2;
 359                      }
 360                  }
 361                  $friendships[ $friendship->id ] = $friendship;
 362              }
 363  
 364          }
 365  
 366          // Sort the results on a column name.
 367          if ( in_array( $r['order_by'], array( 'id', 'initiator_user_id', 'friend_user_id' ) ) ) {
 368              $friendships = bp_sort_by_key( $friendships, $r['order_by'], 'num', true );
 369          }
 370  
 371          // Adjust the sort direction of the results.
 372          if ( 'ASC' === strtoupper( $r['sort_order'] ) ) {
 373              // `true` to preserve keys.
 374              $friendships = array_reverse( $friendships, true );
 375          }
 376  
 377          // Paginate the results.
 378          if ( $r['per_page'] && $r['page'] ) {
 379              $start       = ( $r['page'] - 1 ) * ( $r['per_page'] );
 380              $friendships = array_slice( $friendships, $start, $r['per_page'] );
 381          }
 382  
 383          return $friendships;
 384      }
 385  
 386      /**
 387       * Get all friendship IDs for a user.
 388       *
 389       * @since 2.7.0
 390       *
 391       * @global BuddyPress $bp The one true BuddyPress instance.
 392       * @global wpdb $wpdb WordPress database object.
 393       *
 394       * @param int $user_id ID of the user.
 395       * @return array
 396       */
 397  	public static function get_friendship_ids_for_user( $user_id ) {
 398          global $wpdb;
 399  
 400          $bp = buddypress();
 401  
 402          $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 ) );
 403  
 404          return $friendship_ids;
 405      }
 406  
 407      /**
 408       * Get the IDs of a given user's friends.
 409       *
 410       * @since 1.0.0
 411       *
 412       * @param int  $user_id              ID of the user whose friends are being retrieved.
 413       * @param bool $friend_requests_only Optional. Whether to fetch
 414       *                                   unaccepted requests only. Default: false.
 415       * @param bool $assoc_arr            Optional. True to receive an array of arrays
 416       *                                   keyed as 'user_id' => $user_id; false to get a one-dimensional
 417       *                                   array of user IDs. Default: false.
 418       * @return array $fids IDs of friends for provided user.
 419       */
 420  	public static function get_friend_user_ids( $user_id, $friend_requests_only = false, $assoc_arr = false ) {
 421  
 422          if ( ! empty( $friend_requests_only ) ) {
 423              $args = array(
 424                  'is_confirmed'   => 0,
 425                  'friend_user_id' => $user_id,
 426              );
 427          } else {
 428              $args = array(
 429                  'is_confirmed' => 1,
 430              );
 431          }
 432  
 433          $friendships = self::get_friendships( $user_id, $args );
 434  
 435          $fids = array();
 436          foreach ( $friendships as $friendship ) {
 437              if ( ! empty( $assoc_arr ) ) {
 438                  $fids[] = array( 'user_id' => ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id );
 439              } else {
 440                  $fids[] = ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id;
 441              }
 442          }
 443  
 444          return array_map( 'intval', $fids );
 445      }
 446  
 447      /**
 448       * Get the ID of the friendship object, if any, between a pair of users.
 449       *
 450       * @since 1.0.0
 451       *
 452       * @param int $user_id   The ID of the first user.
 453       * @param int $friend_id The ID of the second user.
 454       * @return int|null The ID of the friendship object if found, otherwise null.
 455       */
 456  	public static function get_friendship_id( $user_id, $friend_id ) {
 457          $friendship_id = null;
 458  
 459          // Can't friend yourself.
 460          if ( $user_id === $friend_id ) {
 461              return $friendship_id;
 462          }
 463  
 464          /*
 465           * Find friendships where the possible_friend_userid is the
 466           * initiator or friend.
 467           */
 468          $args = array(
 469              'initiator_user_id' => $friend_id,
 470              'friend_user_id'    => $friend_id,
 471          );
 472  
 473          $result = self::get_friendships( $user_id, $args, 'OR' );
 474          if ( $result ) {
 475              $friendship_id = current( $result )->id;
 476          }
 477          return $friendship_id;
 478      }
 479  
 480      /**
 481       * Get a list of IDs of users who have requested friendship of a given user.
 482       *
 483       * @since 1.2.0
 484       *
 485       * @param int $user_id The ID of the user who has received the
 486       *                     friendship requests.
 487       * @return array|bool An array of user IDs or false if none are found.
 488       */
 489  	public static function get_friendship_request_user_ids( $user_id ) {
 490          $friend_requests = wp_cache_get( $user_id, 'bp_friends_requests' );
 491  
 492          if ( false === $friend_requests ) {
 493              $friend_requests = self::get_friend_user_ids( $user_id, true );
 494  
 495              wp_cache_set( $user_id, $friend_requests, 'bp_friends_requests' );
 496          }
 497  
 498          // Integer casting.
 499          if ( ! empty( $friend_requests ) ) {
 500              $friend_requests = array_map( 'intval', $friend_requests );
 501          }
 502  
 503          return $friend_requests;
 504      }
 505  
 506      /**
 507       * Get a total friend count for a given user.
 508       *
 509       * @since 1.0.0
 510       *
 511       * @param int $user_id Optional. ID of the user whose friendships you
 512       *                     are counting. Default: displayed user (if any), otherwise
 513       *                     logged-in user.
 514       * @return int Friend count for the user.
 515       */
 516  	public static function total_friend_count( $user_id = 0 ) {
 517  
 518          if ( empty( $user_id ) ) {
 519              $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id();
 520          }
 521  
 522          /*
 523           * This is stored in 'total_friend_count' usermeta.
 524           * This function will recalculate, update and return.
 525           */
 526  
 527          $args        = array( 'is_confirmed' => 1 );
 528          $friendships = self::get_friendships( $user_id, $args );
 529          $count       = count( $friendships );
 530  
 531          // Do not update meta if user has never had friends.
 532          if ( ! $count && ! bp_get_user_meta( $user_id, 'total_friend_count', true ) ) {
 533              return 0;
 534          }
 535  
 536          bp_update_user_meta( $user_id, 'total_friend_count', (int) $count );
 537  
 538          return absint( $count );
 539      }
 540  
 541      /**
 542       * Search the friends of a user by a search string.
 543       *
 544       * @todo Optimize this function.
 545       *
 546       * @since 1.0.0
 547       *
 548       * @global BuddyPress $bp The one true BuddyPress instance.
 549       * @global wpdb $wpdb WordPress database object.
 550       *
 551       * @param string   $filter  The search string, matched against xprofile
 552       *                        fields (if available), or usermeta 'nickname' field.
 553       * @param int      $user_id ID of the user whose friends are being searched.
 554       * @param int|null $limit   Optional. Max number of friends to return.
 555       * @param int|null $page    Optional. The page of results to return. Default:
 556       *                          null (no pagination - return all results).
 557       * @return array|bool On success, an array: {
 558       *     @type array $friends IDs of friends returned by the query.
 559       *     @type int   $count   Total number of friends (disregarding
 560       *                          pagination) who match the search.
 561       * }. Returns false on failure.
 562       */
 563  	public static function search_friends( $filter, $user_id, $limit = null, $page = null ) {
 564          global $wpdb;
 565  
 566          $bp = buddypress();
 567  
 568          if ( empty( $user_id ) ) {
 569              $user_id = bp_loggedin_user_id();
 570          }
 571  
 572          // Only search for matching strings at the beginning of the
 573          // name (@todo - figure out why this restriction).
 574          $search_terms_like = bp_esc_like( $filter ) . '%';
 575  
 576          $pag_sql = '';
 577          if ( ! empty( $limit ) && ! empty( $page ) ) {
 578              $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) );
 579          }
 580  
 581          $friend_ids = self::get_friend_user_ids( $user_id );
 582          if ( ! $friend_ids ) {
 583              return false;
 584          }
 585  
 586          // Get all the user ids for the current user's friends.
 587          $fids = implode( ',', wp_parse_id_list( $friend_ids ) );
 588  
 589          if ( empty( $fids ) ) {
 590              return false;
 591          }
 592  
 593          // Filter the user_ids based on the search criteria.
 594          if ( bp_is_active( 'xprofile' ) ) {
 595              $sql       = $wpdb->prepare( "SELECT DISTINCT user_id FROM {$bp->profile->table_name_data} WHERE user_id IN ({$fids}) AND value LIKE %s {$pag_sql}", $search_terms_like );
 596              $total_sql = $wpdb->prepare( "SELECT COUNT(DISTINCT user_id) FROM {$bp->profile->table_name_data} WHERE user_id IN ({$fids}) AND value LIKE %s", $search_terms_like );
 597          } else {
 598              $sql       = $wpdb->prepare( "SELECT DISTINCT user_id FROM {$wpdb->usermeta} WHERE user_id IN ({$fids}) AND meta_key = 'nickname' AND meta_value LIKE %s {$pag_sql}", $search_terms_like );
 599              $total_sql = $wpdb->prepare( "SELECT COUNT(DISTINCT user_id) FROM {$wpdb->usermeta} WHERE user_id IN ({$fids}) AND meta_key = 'nickname' AND meta_value LIKE %s", $search_terms_like );
 600          }
 601  
 602          $filtered_friend_ids = $wpdb->get_col( $sql );
 603          $total_friend_ids    = $wpdb->get_var( $total_sql );
 604  
 605          if ( empty( $filtered_friend_ids ) ) {
 606              return false;
 607          }
 608  
 609          return array(
 610              'friends' => array_map( 'intval', $filtered_friend_ids ),
 611              'total'   => (int) $total_friend_ids,
 612          );
 613      }
 614  
 615      /**
 616       * Check friendship status between two users.
 617       *
 618       * Note that 'pending' means that $initiator_userid has sent a friend
 619       * request to $possible_friend_userid that has not yet been approved,
 620       * while 'awaiting_response' is the other way around ($possible_friend_userid
 621       * sent the initial request).
 622       *
 623       * @since 1.0.0
 624       *
 625       * @param int $initiator_userid       The ID of the user who is the initiator
 626       *                                    of the potential friendship/request.
 627       * @param int $possible_friend_userid The ID of the user who is the
 628       *                                    recipient of the potential friendship/request.
 629       * @return string|false $value The friendship status, from among 'not_friends',
 630       *                             'is_friend', 'pending', and 'awaiting_response'.
 631       */
 632  	public static function check_is_friend( $initiator_userid, $possible_friend_userid ) {
 633  
 634          if ( empty( $initiator_userid ) || empty( $possible_friend_userid ) ) {
 635              return false;
 636          }
 637  
 638          // Can't friend yourself.
 639          if ( $initiator_userid === $possible_friend_userid ) {
 640              return 'not_friends';
 641          }
 642  
 643          self::update_bp_friends_cache( $initiator_userid, $possible_friend_userid );
 644  
 645          return bp_core_get_incremented_cache( $initiator_userid . ':' . $possible_friend_userid, 'bp_friends' );
 646      }
 647  
 648      /**
 649       * Find uncached friendships between a user and one or more other users and cache them.
 650       *
 651       * @since 3.0.0
 652       *
 653       * @global BuddyPress $bp The one true BuddyPress instance.
 654       * @global wpdb $wpdb WordPress database object.
 655       *
 656       * @param int              $user_id             The ID of the primary user for whom we want
 657       *                                              to check friendships statuses.
 658       * @param int|array|string $possible_friend_ids The IDs of the one or more users
 659       *                                              to check friendship status with primary user.
 660       */
 661  	public static function update_bp_friends_cache( $user_id, $possible_friend_ids ) {
 662          global $wpdb;
 663  
 664          $bp                  = buddypress();
 665          $possible_friend_ids = wp_parse_id_list( $possible_friend_ids );
 666  
 667          $fetch = array();
 668          foreach ( $possible_friend_ids as $friend_id ) {
 669              // Check for cached items in both friendship directions.
 670              if ( false === bp_core_get_incremented_cache( $user_id . ':' . $friend_id, 'bp_friends' )
 671                  || false === bp_core_get_incremented_cache( $friend_id . ':' . $user_id, 'bp_friends' ) ) {
 672                  $fetch[] = $friend_id;
 673              }
 674          }
 675  
 676          if ( empty( $fetch ) ) {
 677              return;
 678          }
 679  
 680          $friend_ids_sql = implode( ',', array_unique( $fetch ) );
 681          $sql = $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 ({$friend_ids_sql}) ) OR (initiator_user_id IN ({$friend_ids_sql}) AND friend_user_id = %d )", $user_id, $user_id );
 682          $friendships = $wpdb->get_results( $sql );
 683  
 684          // Use $handled to keep track of all of the $possible_friend_ids we've matched.
 685          $handled = array();
 686          foreach ( $friendships as $friendship ) {
 687              $initiator_user_id = (int) $friendship->initiator_user_id;
 688              $friend_user_id    = (int) $friendship->friend_user_id;
 689              if ( 1 === (int) $friendship->is_confirmed ) {
 690                  $status_initiator = $status_friend = 'is_friend';
 691              } else {
 692                  $status_initiator = 'pending';
 693                  $status_friend    = 'awaiting_response';
 694              }
 695              bp_core_set_incremented_cache( $initiator_user_id . ':' . $friend_user_id, 'bp_friends', $status_initiator );
 696              bp_core_set_incremented_cache( $friend_user_id . ':' . $initiator_user_id, 'bp_friends', $status_friend );
 697  
 698              $handled[] = ( $initiator_user_id === $user_id ) ? $friend_user_id : $initiator_user_id;
 699          }
 700  
 701          // Set all those with no matching entry to "not friends" status.
 702          $not_friends = array_diff( $fetch, $handled );
 703  
 704          foreach ( $not_friends as $not_friend_id ) {
 705              bp_core_set_incremented_cache( $user_id . ':' . $not_friend_id, 'bp_friends', 'not_friends' );
 706              bp_core_set_incremented_cache( $not_friend_id . ':' . $user_id, 'bp_friends', 'not_friends' );
 707          }
 708      }
 709  
 710      /**
 711       * Get the last active date of many users at once.
 712       *
 713       * @todo Why is this in the Friends component?
 714       *
 715       * @since 1.0.0
 716       *
 717       * @param array $user_ids IDs of users whose last_active meta is
 718       *                        being queried.
 719       * @return array $retval Array of last_active values + user_ids.
 720       */
 721  	public static function get_bulk_last_active( $user_ids ) {
 722          $last_activities = BP_Core_User::get_last_activity( $user_ids );
 723  
 724          // Sort and structure as expected in legacy function.
 725          usort( $last_activities, function( $a, $b ) {
 726              if ( $a['date_recorded'] === $b['date_recorded'] ) {
 727                  return 0;
 728              }
 729  
 730              return ( strtotime( $a['date_recorded'] ) < strtotime( $b['date_recorded'] ) ) ? 1 : -1;
 731          } );
 732  
 733          $retval = array();
 734          foreach ( $last_activities as $last_activity ) {
 735              $u                = new stdClass();
 736              $u->last_activity = $last_activity['date_recorded'];
 737              $u->user_id       = $last_activity['user_id'];
 738  
 739              $retval[] = $u;
 740          }
 741  
 742          return $retval;
 743      }
 744  
 745      /**
 746       * Mark a friendship as accepted.
 747       *
 748       * @since 1.0.0
 749       *
 750       * @global BuddyPress $bp The one true BuddyPress instance.
 751       * @global wpdb $wpdb WordPress database object.
 752       *
 753       * @param int $friendship_id ID of the friendship to be accepted.
 754       * @return int Number of database rows updated.
 755       */
 756  	public static function accept( $friendship_id ) {
 757          global $wpdb;
 758  
 759          $bp = buddypress();
 760  
 761          return $wpdb->query( $wpdb->prepare( "UPDATE {$bp->friends->table_name} SET is_confirmed = 1, date_created = %s WHERE id = %d AND friend_user_id = %d", bp_core_current_time(), $friendship_id, bp_loggedin_user_id() ) );
 762      }
 763  
 764      /**
 765       * Remove a friendship or a friendship request INITIATED BY the logged-in user.
 766       *
 767       * @since 1.6.0
 768       *
 769       * @global BuddyPress $bp The one true BuddyPress instance.
 770       * @global wpdb $wpdb WordPress database object.
 771       *
 772       * @param int $friendship_id ID of the friendship to be withdrawn.
 773       * @return int Number of database rows deleted.
 774       */
 775  	public static function withdraw( $friendship_id ) {
 776          global $wpdb;
 777  
 778          $bp = buddypress();
 779  
 780          return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE id = %d AND initiator_user_id = %d", $friendship_id, bp_loggedin_user_id() ) );
 781      }
 782  
 783      /**
 784       * Remove a friendship or a friendship request MADE OF the logged-in user.
 785       *
 786       * @since 1.0.0
 787       *
 788       * @global BuddyPress $bp The one true BuddyPress instance.
 789       * @global wpdb $wpdb WordPress database object.
 790       *
 791       * @param int $friendship_id ID of the friendship to be rejected.
 792       * @return int Number of database rows deleted.
 793       */
 794  	public static function reject( $friendship_id ) {
 795          global $wpdb;
 796  
 797          $bp = buddypress();
 798  
 799          return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE id = %d AND friend_user_id = %d", $friendship_id, bp_loggedin_user_id() ) );
 800      }
 801  
 802      /**
 803       * Search users.
 804       *
 805       * @todo Why does this exist, and why is it in bp-friends?
 806       *
 807       * @since 1.0.0
 808       *
 809       * @global BuddyPress $bp The one true BuddyPress instance.
 810       * @global wpdb $wpdb WordPress database object.
 811       *
 812       * @param string   $filter  String to search by.
 813       * @param int      $user_id A user ID param that is unused.
 814       * @param int|null $limit   Optional. Max number of records to return.
 815       * @param int|null $page    Optional. Number of the page to return. Default:
 816       *                          false (no pagination - return all results).
 817       * @return array $filtered_ids IDs of users who match the query.
 818       */
 819  	public static function search_users( $filter, $user_id, $limit = null, $page = null ) {
 820          global $wpdb;
 821  
 822          // Only search for matching strings at the beginning of the
 823          // name (@todo - figure out why this restriction).
 824          $search_terms_like = bp_esc_like( $filter ) . '%';
 825  
 826          $usermeta_table = $wpdb->base_prefix . 'usermeta';
 827          $users_table    = $wpdb->base_prefix . 'users';
 828  
 829          $pag_sql = '';
 830          if ( ! empty( $limit ) && ! empty( $page ) ) {
 831              $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * intval( $limit ) ), intval( $limit ) );
 832          }
 833  
 834          $bp = buddypress();
 835  
 836          // Filter the user_ids based on the search criteria.
 837          if ( bp_is_active( 'xprofile' ) ) {
 838              $sql = $wpdb->prepare( "SELECT DISTINCT d.user_id as id FROM {$bp->profile->table_name_data} d, {$users_table} u WHERE d.user_id = u.id AND d.value LIKE %s ORDER BY d.value DESC {$pag_sql}", $search_terms_like );
 839          } else {
 840              $sql = $wpdb->prepare( "SELECT DISTINCT user_id as id FROM {$usermeta_table} WHERE meta_value LIKE %s ORDER BY d.value DESC {$pag_sql}", $search_terms_like );
 841          }
 842  
 843          $filtered_fids = $wpdb->get_col( $sql );
 844  
 845          if ( empty( $filtered_fids ) ) {
 846              return false;
 847          }
 848  
 849          return $filtered_fids;
 850      }
 851  
 852      /**
 853       * Get a count of users who match a search term.
 854       *
 855       * @todo Why does this exist, and why is it in bp-friends?
 856       *
 857       * @since 1.0.0
 858       *
 859       * @global BuddyPress $bp The one true BuddyPress instance.
 860       * @global wpdb $wpdb WordPress database object.
 861       *
 862       * @param string $filter Search term.
 863       * @return int Count of users matching the search term.
 864       */
 865  	public static function search_users_count( $filter ) {
 866          global $wpdb;
 867  
 868          // Only search for matching strings at the beginning of the
 869          // name (@todo - figure out why this restriction).
 870          $search_terms_like = bp_esc_like( $filter ) . '%';
 871  
 872          $usermeta_table = $wpdb->prefix . 'usermeta';
 873          $users_table    = $wpdb->base_prefix . 'users';
 874  
 875          $bp = buddypress();
 876  
 877          // Filter the user_ids based on the search criteria.
 878          if ( bp_is_active( 'xprofile' ) ) {
 879              $sql = $wpdb->prepare( "SELECT COUNT(DISTINCT d.user_id) FROM {$bp->profile->table_name_data} d, {$users_table} u WHERE d.user_id = u.id AND d.value LIKE %s", $search_terms_like );
 880          } else {
 881              $sql = $wpdb->prepare( "SELECT COUNT(DISTINCT user_id) FROM {$usermeta_table} WHERE meta_value LIKE %s", $search_terms_like );
 882          }
 883  
 884          $user_count = $wpdb->get_col( $sql );
 885  
 886          if ( empty( $user_count ) ) {
 887              return false;
 888          }
 889  
 890          return $user_count[0];
 891      }
 892  
 893      /**
 894       * Sort a list of user IDs by their display names.
 895       *
 896       * @todo Why does this exist, and why is it in bp-friends?
 897       *
 898       * @since 1.0.0
 899       *
 900       * @global BuddyPress $bp The one true BuddyPress instance.
 901       * @global wpdb $wpdb WordPress database object.
 902       *
 903       * @param array $user_ids Array of user IDs.
 904       * @return array|bool User IDs, sorted by the associated display names.
 905       *                    False if XProfile component is not active.
 906       */
 907  	public static function sort_by_name( $user_ids ) {
 908          global $wpdb;
 909  
 910          if ( ! bp_is_active( 'xprofile' ) ) {
 911              return false;
 912          }
 913  
 914          $bp = buddypress();
 915  
 916          $user_ids = implode( ',', wp_parse_id_list( $user_ids ) );
 917  
 918          return $wpdb->get_results( $wpdb->prepare( "SELECT user_id FROM {$bp->profile->table_name_data} pd, {$bp->profile->table_name_fields} pf WHERE pf.id = pd.field_id AND pf.name = %s AND pd.user_id IN ( {$user_ids} ) ORDER BY pd.value ASC", bp_xprofile_fullname_field_name() ) );
 919      }
 920  
 921      /**
 922       * Get a list of random friend IDs.
 923       *
 924       * @since 1.0.0
 925       *
 926       * @global BuddyPress $bp The one true BuddyPress instance.
 927       * @global wpdb $wpdb WordPress database object.
 928       *
 929       * @param int $user_id       ID of the user whose friends are being retrieved.
 930       * @param int $total_friends Optional. Number of random friends to get.
 931       *                           Default: 5.
 932       * @return array|false An array of random friend user IDs on success;
 933       *                     false if none are found.
 934       */
 935  	public static function get_random_friends( $user_id, $total_friends = 5 ) {
 936          global $wpdb;
 937  
 938          $bp      = buddypress();
 939          $fids    = array();
 940          $sql     = $wpdb->prepare( "SELECT friend_user_id, initiator_user_id FROM {$bp->friends->table_name} WHERE (friend_user_id = %d || initiator_user_id = %d) && is_confirmed = 1 ORDER BY rand() LIMIT %d", $user_id, $user_id, $total_friends );
 941          $results = $wpdb->get_results( $sql );
 942  
 943          for ( $i = 0, $count = count( $results ); $i < $count; ++$i ) {
 944              $fids[] = ( $results[ $i ]->friend_user_id === $user_id ) ? $results[ $i ]->initiator_user_id : $results[ $i ]->friend_user_id;
 945          }
 946  
 947          // Remove duplicates.
 948          if ( count( $fids ) > 0 ) {
 949              return array_flip( array_flip( $fids ) );
 950          }
 951  
 952          return false;
 953      }
 954  
 955      /**
 956       * Get a count of a user's friends who can be invited to a given group.
 957       *
 958       * Users can invite any of their friends except:
 959       *
 960       * - users who are already in the group
 961       * - users who have a pending invite to the group
 962       * - users who have been banned from the group
 963       *
 964       * @todo Need to do a group component check before using group functions.
 965       *
 966       * @since 1.0.0
 967       *
 968       * @param int $user_id  ID of the user whose friends are being counted.
 969       * @param int $group_id ID of the group friends are being invited to.
 970       * @return bool|int False if group component is not active, and friend count.
 971       */
 972  	public static function get_invitable_friend_count( $user_id, $group_id ) {
 973  
 974          if ( ! bp_is_active( 'group' ) ) {
 975              return false;
 976          }
 977  
 978          // Setup some data we'll use below.
 979          $is_group_admin  = groups_is_user_admin( $user_id, $group_id );
 980          $friend_ids      = self::get_friend_user_ids( $user_id );
 981          $invitable_count = 0;
 982  
 983          for ( $i = 0, $count = count( $friend_ids ); $i < $count; ++$i ) {
 984  
 985              // If already a member, they cannot be invited again.
 986              if ( groups_is_user_member( (int) $friend_ids[ $i ], $group_id ) ) {
 987                  continue;
 988              }
 989  
 990              // If user already has invite, they cannot be added.
 991              if ( groups_check_user_has_invite( (int) $friend_ids[ $i ], $group_id ) ) {
 992                  continue;
 993              }
 994  
 995              // If user is not group admin and friend is banned, they cannot be invited.
 996              if ( ( false === $is_group_admin ) && groups_is_user_banned( (int) $friend_ids[ $i ], $group_id ) ) {
 997                  continue;
 998              }
 999  
1000              $invitable_count++;
1001          }
1002  
1003          return $invitable_count;
1004      }
1005  
1006      /**
1007       * Get friendship objects by ID (or an array of IDs).
1008       *
1009       * @since 2.7.0
1010       *
1011       * @global BuddyPress $bp The one true BuddyPress instance.
1012       * @global wpdb $wpdb WordPress database object.
1013       *
1014       * @param int|string|array $friendship_ids Single friendship ID or comma-separated/array list of friendship IDs.
1015       * @return array
1016       */
1017  	public static function get_friendships_by_id( $friendship_ids ) {
1018          global $wpdb;
1019  
1020          $bp = buddypress();
1021  
1022          $friendship_ids = implode( ',', wp_parse_id_list( $friendship_ids ) );
1023          return $wpdb->get_results( "SELECT * FROM {$bp->friends->table_name} WHERE id IN ({$friendship_ids})" );
1024      }
1025  
1026      /**
1027       * Get the friend user IDs for a given friendship.
1028       *
1029       * @since 1.0.0
1030       *
1031       * @param int $friendship_id ID of the friendship.
1032       * @return null|stdClass
1033       */
1034  	public static function get_user_ids_for_friendship( $friendship_id ) {
1035          $friendship = new BP_Friends_Friendship( $friendship_id, false, false );
1036  
1037          if ( empty( $friendship->id ) ) {
1038              return null;
1039          }
1040  
1041          $retval                    = new StdClass();
1042          $retval->friend_user_id    = $friendship->friend_user_id;
1043          $retval->initiator_user_id = $friendship->initiator_user_id;
1044  
1045          return $retval;
1046      }
1047  
1048      /**
1049       * Delete all friendships and friend notifications related to a user.
1050       *
1051       * @since 1.0.0
1052       *
1053       * @global BuddyPress $bp The one true BuddyPress instance.
1054       * @global wpdb $wpdb WordPress database object.
1055       *
1056       * @param int $user_id ID of the user being expunged.
1057       */
1058  	public static function delete_all_for_user( $user_id ) {
1059          global $wpdb;
1060  
1061          $bp = buddypress();
1062  
1063          // Get all friendships, of any status, for the user.
1064          $friendships    = self::get_friendships( $user_id );
1065          $friend_ids     = array();
1066          $friendship_ids = array();
1067          foreach ( $friendships as $friendship ) {
1068              $friendship_ids[] = $friendship->id;
1069              if ( $friendship->is_confirmed ) {
1070                  $friend_ids[] = ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id;
1071              }
1072          }
1073  
1074          // Delete the friendships from the database.
1075          if ( $friendship_ids ) {
1076              $friendship_ids_sql = implode( ',', wp_parse_id_list( $friendship_ids ) );
1077              $wpdb->query( "DELETE FROM {$bp->friends->table_name} WHERE id IN ({$friendship_ids_sql})" );
1078          }
1079  
1080          // Delete friend request notifications for members who have a
1081          // notification from this user.
1082          if ( bp_is_active( 'notifications' ) ) {
1083              $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 ) );
1084          }
1085  
1086          // Clean up the friendships cache.
1087          foreach ( $friendship_ids as $friendship_id ) {
1088              wp_cache_delete( $friendship_id, 'bp_friends_friendships' );
1089          }
1090  
1091          // Loop through friend_ids to scrub user caches and update total count metas.
1092          foreach ( (array) $friend_ids as $friend_id ) {
1093              // Delete cached friendships.
1094              wp_cache_delete( $friend_id, 'bp_friends_friendships_for_user' );
1095  
1096              self::total_friend_count( $friend_id );
1097          }
1098  
1099          // Delete cached friendships.
1100          wp_cache_delete( $user_id, 'bp_friends_friendships_for_user' );
1101      }
1102  }


Generated: Sun Oct 24 01:00:54 2021 Cross-referenced by PHPXref 0.7.1