Ticket #7435: 7435.diff
File 7435.diff, 17.4 KB (added by , 7 years ago) |
---|
-
src/bp-xprofile/bp-xprofile-cache.php
diff --git src/bp-xprofile/bp-xprofile-cache.php src/bp-xprofile/bp-xprofile-cache.php index dc372e77b..ba6aca7fb 100644
function bp_xprofile_reset_fields_by_name_cache_incrementor() { 287 287 } 288 288 add_action( 'xprofile_field_before_save', 'bp_xprofile_reset_fields_by_name_cache_incrementor' ); 289 289 290 /** 291 * Resets all incremented bp_xprofile_groups caches. 292 * 293 * @since 4.0.0 294 */ 295 function bp_xprofile_reset_groups_cache_incrementor() { 296 bp_core_reset_incrementor( 'bp_xprofile_groups' ); 297 } 298 add_action( 'xprofile_group_after_delete', 'bp_xprofile_reset_groups_cache_incrementor' ); 299 add_action( 'xprofile_group_after_save', 'bp_xprofile_reset_groups_cache_incrementor' ); 300 add_action( 'xprofile_field_after_delete', 'bp_xprofile_reset_groups_cache_incrementor' ); 301 add_action( 'xprofile_field_after_save', 'bp_xprofile_reset_groups_cache_incrementor' ); 302 290 303 // List actions to clear super cached pages on, if super cache is installed. 291 304 add_action( 'xprofile_updated_profile', 'bp_core_clear_cache' ); -
src/bp-xprofile/classes/class-bp-xprofile-field.php
diff --git src/bp-xprofile/classes/class-bp-xprofile-field.php src/bp-xprofile/classes/class-bp-xprofile-field.php index afc10747d..e96f69fdb 100644
class BP_XProfile_Field { 977 977 $sql = $wpdb->prepare( "UPDATE {$table_name} SET field_order = %d, group_id = %d WHERE id = %d", $position, $field_group_id, $field_id ); 978 978 $parent = $wpdb->query( $sql ); 979 979 980 $retval = false; 981 980 982 // Update $field_id with new $position and $field_group_id. 981 983 if ( ! empty( $parent ) && ! is_wp_error( $parent ) ) { 982 984 … … class BP_XProfile_Field { 984 986 $sql = $wpdb->prepare( "UPDATE {$table_name} SET group_id = %d WHERE parent_id = %d", $field_group_id, $field_id ); 985 987 $wpdb->query( $sql ); 986 988 987 // Invalidate profile field cache.989 // Invalidate profile field and group query cache. 988 990 wp_cache_delete( $field_id, 'bp_xprofile_fields' ); 989 991 990 return$parent;992 $retval = $parent; 991 993 } 992 994 993 return false; 995 bp_core_reset_incrementor( 'bp_xprofile_groups' ); 996 997 return $retval; 994 998 } 995 999 996 1000 /** -
src/bp-xprofile/classes/class-bp-xprofile-group.php
diff --git src/bp-xprofile/classes/class-bp-xprofile-group.php src/bp-xprofile/classes/class-bp-xprofile-group.php index 27a4d8c1a..7d39bc54f 100644
class BP_XProfile_Group { 288 288 'data' => array(), 289 289 ); 290 290 291 // WHERE.292 if ( ! empty( $r['profile_group_id'] ) ) {293 $where_sql = $wpdb->prepare( 'WHERE g.id = %d', $r['profile_group_id'] );294 } elseif ( $r['exclude_groups'] ) {295 $exclude = join( ',', wp_parse_id_list( $r['exclude_groups'] ) );296 $where_sql = "WHERE g.id NOT IN ({$exclude})";297 } else {298 $where_sql = '';299 }300 301 291 $bp = buddypress(); 302 292 303 // Include or exclude empty groups. 304 if ( ! empty( $r['hide_empty_groups'] ) ) { 305 $group_ids = $wpdb->get_col( "SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g INNER JOIN {$bp->profile->table_name_fields} f ON g.id = f.group_id {$where_sql} ORDER BY g.group_order ASC" ); 306 } else { 307 $group_ids = $wpdb->get_col( "SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g {$where_sql} ORDER BY g.group_order ASC" ); 308 } 293 $group_ids = self::get_group_ids( $r ); 309 294 310 295 // Get all group data. 311 296 $groups = self::get_group_data( $group_ids ); … … class BP_XProfile_Group { 326 311 return $groups; 327 312 } 328 313 329 // Setup IN query from group IDs. 330 $group_ids_in = implode( ',', (array) $group_ids ); 331 332 // Support arrays and comma-separated strings. 333 $exclude_fields_cs = wp_parse_id_list( $r['exclude_fields'] ); 334 335 // Visibility - Handled here so as not to be overridden by sloppy use of the 336 // exclude_fields parameter. See bp_xprofile_get_hidden_fields_for_user(). 337 $hidden_user_fields = bp_xprofile_get_hidden_fields_for_user( $r['user_id'] ); 338 $exclude_fields_cs = array_merge( $exclude_fields_cs, $hidden_user_fields ); 339 $exclude_fields_cs = implode( ',', $exclude_fields_cs ); 340 341 // Set up NOT IN query for excluded field IDs. 342 if ( ! empty( $exclude_fields_cs ) ) { 343 $exclude_fields_sql = "AND id NOT IN ({$exclude_fields_cs})"; 344 } else { 345 $exclude_fields_sql = ''; 346 } 347 348 // Set up IN query for included field IDs. 349 $include_field_ids = array(); 350 351 // Member-type restrictions. 352 if ( bp_get_member_types() ) { 353 if ( $r['user_id'] || false !== $r['member_type'] ) { 354 $member_types = $r['member_type']; 355 if ( $r['user_id'] ) { 356 $member_types = bp_get_member_type( $r['user_id'], false ); 357 if ( empty( $member_types ) ) { 358 $member_types = array( 'null' ); 359 } 360 } 361 362 $member_types_fields = BP_XProfile_Field::get_fields_for_member_type( $member_types ); 363 $include_field_ids += array_keys( $member_types_fields ); 364 } 365 } 366 367 $in_sql = ''; 368 if ( ! empty( $include_field_ids ) ) { 369 $include_field_ids_cs = implode( ',', array_map( 'intval', $include_field_ids ) ); 370 $in_sql = " AND id IN ({$include_field_ids_cs}) "; 371 } 372 373 // Fetch the fields. 374 $field_ids = $wpdb->get_col( "SELECT id FROM {$bp->profile->table_name_fields} WHERE group_id IN ( {$group_ids_in} ) AND parent_id = 0 {$exclude_fields_sql} {$in_sql} ORDER BY field_order" ); 314 $field_ids = self::get_group_field_ids( $group_ids, $r ); 375 315 376 316 foreach( $groups as $group ) { 377 317 $group->fields = array(); … … class BP_XProfile_Group { 498 438 return $groups; 499 439 } 500 440 441 /** 442 * Gets group IDs, based on passed parameters. 443 * 444 * @since 4.0.0 445 * 446 * @param array $args { 447 * Array of optional arguments: 448 * @type int $profile_group_id Limit results to a single profile group. Default false. 449 * @type array $exclude_groups Comma-separated list or array of group IDs to exclude. Default false. 450 * @type bool $hide_empty_groups True to hide groups that don't have any fields. Default: false. 451 * } 452 * @return array 453 */ 454 public static function get_group_ids( $args = array() ) { 455 global $wpdb; 456 457 $r = array_merge( 458 array( 459 'profile_group_id' => false, 460 'exclude_groups' => false, 461 'hide_empty_groups' => false, 462 ), 463 $args 464 ); 465 466 $bp = buddypress(); 467 468 if ( ! empty( $r['profile_group_id'] ) ) { 469 $where_sql = $wpdb->prepare( 'WHERE g.id = %d', $r['profile_group_id'] ); 470 } elseif ( $r['exclude_groups'] ) { 471 $exclude = join( ',', wp_parse_id_list( $r['exclude_groups'] ) ); 472 $where_sql = "WHERE g.id NOT IN ({$exclude})"; 473 } else { 474 $where_sql = ''; 475 } 476 477 // Include or exclude empty groups. 478 if ( ! empty( $r['hide_empty_groups'] ) ) { 479 $group_ids_sql = "SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g INNER JOIN {$bp->profile->table_name_fields} f ON g.id = f.group_id {$where_sql} ORDER BY g.group_order ASC"; 480 } else { 481 $group_ids_sql = "SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g {$where_sql} ORDER BY g.group_order ASC"; 482 } 483 484 $cached = bp_core_get_incremented_cache( $group_ids_sql, 'bp_xprofile_groups' ); 485 if ( false === $cached ) { 486 $group_ids = $wpdb->get_col( $group_ids_sql ); 487 bp_core_set_incremented_cache( $group_ids_sql, 'bp_xprofile_groups', $group_ids ); 488 } else { 489 $group_ids = $cached; 490 } 491 492 return array_map( 'intval', $group_ids ); 493 } 494 495 /** 496 * Gets group field IDs, based on passed parameters. 497 * 498 * @since 4.0.0 499 * 500 * @param array $group_ids Array of group IDs. 501 * @param array $args { 502 * Array of optional arguments: 503 * @type array $exclude_fields Comma-separated list or array of field IDs to exclude. 504 * Default empty. 505 * @type int $user_id Limit results to fields associated with a given user's 506 * member type. Default empty. 507 * @type array|string $member_type Limit fields by those restricted to a given member type, or array of 508 * member types. If `$user_id` is provided, the value of `$member_type` 509 * is honored. 510 * } 511 * @return array 512 */ 513 public static function get_group_field_ids( $group_ids, $args = array() ) { 514 global $wpdb; 515 516 $r = array_merge( 517 array( 518 'exclude_fields' => false, 519 'user_id' => false, 520 'member_type' => false, 521 ), 522 $args 523 ); 524 525 $bp = buddypress(); 526 527 // Setup IN query from group IDs. 528 if ( empty( $group_ids ) ) { 529 $group_ids = array( 0 ); 530 } 531 $group_ids_in = implode( ',', array_map( 'intval', $group_ids ) ); 532 533 // Support arrays and comma-separated strings. 534 $exclude_fields_cs = wp_parse_id_list( $r['exclude_fields'] ); 535 536 // Visibility - Handled here so as not to be overridden by sloppy use of the 537 // exclude_fields parameter. See bp_xprofile_get_hidden_fields_for_user(). 538 $hidden_user_fields = bp_xprofile_get_hidden_fields_for_user( $r['user_id'] ); 539 $exclude_fields_cs = array_merge( $exclude_fields_cs, $hidden_user_fields ); 540 $exclude_fields_cs = implode( ',', $exclude_fields_cs ); 541 542 // Set up NOT IN query for excluded field IDs. 543 if ( ! empty( $exclude_fields_cs ) ) { 544 $exclude_fields_sql = "AND id NOT IN ({$exclude_fields_cs})"; 545 } else { 546 $exclude_fields_sql = ''; 547 } 548 549 // Set up IN query for included field IDs. 550 $include_field_ids = array(); 551 552 // Member-type restrictions. 553 if ( bp_get_member_types() ) { 554 if ( $r['user_id'] || false !== $r['member_type'] ) { 555 $member_types = $r['member_type']; 556 if ( $r['user_id'] ) { 557 $member_types = bp_get_member_type( $r['user_id'], false ); 558 if ( empty( $member_types ) ) { 559 $member_types = array( 'null' ); 560 } 561 } 562 563 $member_types_fields = BP_XProfile_Field::get_fields_for_member_type( $member_types ); 564 $include_field_ids += array_keys( $member_types_fields ); 565 } 566 } 567 568 $in_sql = ''; 569 if ( ! empty( $include_field_ids ) ) { 570 $include_field_ids_cs = implode( ',', array_map( 'intval', $include_field_ids ) ); 571 $in_sql = " AND id IN ({$include_field_ids_cs}) "; 572 } 573 574 $field_ids_sql = "SELECT id FROM {$bp->profile->table_name_fields} WHERE group_id IN ( {$group_ids_in} ) AND parent_id = 0 {$exclude_fields_sql} {$in_sql} ORDER BY field_order"; 575 576 $cached = bp_core_get_incremented_cache( $field_ids_sql, 'bp_xprofile_groups' ); 577 if ( false === $cached ) { 578 $field_ids = $wpdb->get_col( $field_ids_sql ); 579 bp_core_set_incremented_cache( $field_ids_sql, 'bp_xprofile_groups', $field_ids ); 580 } else { 581 $field_ids = $cached; 582 } 583 584 return array_map( 'intval', $field_ids ); 585 } 586 501 587 /** 502 588 * Get data about a set of groups, based on IDs. 503 589 * … … class BP_XProfile_Group { 613 699 return false; 614 700 } 615 701 616 // Purge profile field group cache.702 // Purge profile field group and group query caches. 617 703 wp_cache_delete( 'all', 'bp_xprofile_groups' ); 704 bp_core_reset_incrementor( 'bp_xprofile_groups' ); 618 705 619 706 $bp = buddypress(); 620 707 -
tests/phpunit/testcases/xprofile/class-bp-xprofile-group.php
diff --git tests/phpunit/testcases/xprofile/class-bp-xprofile-group.php tests/phpunit/testcases/xprofile/class-bp-xprofile-group.php index 879b31c6a..439641233 100644
class BP_Tests_BP_XProfile_Group extends BP_UnitTestCase { 441 441 442 442 $this->assertSame( "Test ' Name", $e1->name ); 443 443 } 444 445 /** 446 * @group BP7435 447 * @group cache 448 */ 449 public function test_group_ids_query_should_be_cached() { 450 global $wpdb; 451 452 $group_ids = array( 1 ); // Default group. 453 $group_ids[] = self::factory()->xprofile_group->create(); 454 $group_ids[] = self::factory()->xprofile_group->create(); 455 $group_ids[] = self::factory()->xprofile_group->create(); 456 457 $params_1 = array( 458 'exclude_groups' => false, 459 ); 460 461 $params_2 = array( 462 'exclude_groups' => array( 0 ), 463 ); 464 465 // Prime cache. 466 $found_1 = BP_XProfile_Group::get_group_ids( $params_1 ); 467 $this->assertEqualSets( $group_ids, $found_1 ); 468 469 $num_queries = $wpdb->num_queries; 470 471 $found_1 = BP_XProfile_Group::get_group_ids( $params_1 ); 472 $this->assertEqualSets( $group_ids, $found_1 ); 473 $this->assertSame( $num_queries, $wpdb->num_queries ); 474 475 // Different parameters should trigger a cache miss. 476 $found_2 = BP_XProfile_Group::get_group_ids( $params_2 ); 477 $this->assertEqualSets( $group_ids, $found_2 ); 478 $this->assertNotSame( $num_queries, $wpdb->num_queries ); 479 } 480 481 /** 482 * @group BP7435 483 * @group cache 484 */ 485 public function test_group_ids_query_cache_should_be_busted_on_group_delete() { 486 $group_ids = array( 1 ); // Default group. 487 $group_ids[1] = self::factory()->xprofile_group->create(); 488 $group_ids[2] = self::factory()->xprofile_group->create(); 489 $group_ids[3] = self::factory()->xprofile_group->create(); 490 491 // Prime cache. 492 $found = BP_XProfile_Group::get_group_ids(); 493 $this->assertContains( $group_ids[1], $found ); 494 495 $g1 = new BP_XProfile_Group( $group_ids[1] ); 496 $g1->delete(); 497 498 $found = BP_XProfile_Group::get_group_ids(); 499 $this->assertNotContains( $group_ids[1], $found ); 500 } 501 502 /** 503 * @group BP7435 504 * @group cache 505 */ 506 public function test_group_ids_query_cache_should_be_busted_on_group_save() { 507 global $wpdb; 508 509 $group_ids = array( 1 ); // Default group. 510 $group_ids[1] = self::factory()->xprofile_group->create(); 511 $group_ids[2] = self::factory()->xprofile_group->create(); 512 $group_ids[3] = self::factory()->xprofile_group->create(); 513 514 // Prime cache. 515 $found = BP_XProfile_Group::get_group_ids(); 516 $this->assertContains( $group_ids[1], $found ); 517 518 $g1 = new BP_XProfile_Group( $group_ids[1] ); 519 $g1->save(); 520 521 $num_queries = $wpdb->num_queries; 522 523 $found = BP_XProfile_Group::get_group_ids(); 524 $this->assertNotSame( $num_queries, $wpdb->num_queries ); 525 } 526 527 /** 528 * @group BP7435 529 * @group cache 530 */ 531 public function test_group_ids_query_cache_should_be_busted_on_field_save() { 532 global $wpdb; 533 534 $group_ids = array( 1 ); // Default group. 535 $group_ids[1] = self::factory()->xprofile_group->create(); 536 $group_ids[2] = self::factory()->xprofile_group->create(); 537 $group_ids[3] = self::factory()->xprofile_group->create(); 538 539 $f = self::factory()->xprofile_field->create( array( 540 'field_group_id' => $group_ids[1], 541 ) ); 542 $field = new BP_XProfile_Field( $f ); 543 544 // Prime cache. 545 $found = BP_XProfile_Group::get_group_ids(); 546 $this->assertContains( $group_ids[1], $found ); 547 548 $field->save(); 549 550 $num_queries = $wpdb->num_queries; 551 552 $found = BP_XProfile_Group::get_group_ids(); 553 $this->assertNotSame( $num_queries, $wpdb->num_queries ); 554 } 555 556 /** 557 * @group BP7435 558 * @group cache 559 */ 560 public function test_group_ids_query_cache_should_be_busted_on_field_delete() { 561 $group_ids = array( 1 ); // Default group. 562 $group_ids[1] = self::factory()->xprofile_group->create(); 563 $group_ids[2] = self::factory()->xprofile_group->create(); 564 $group_ids[3] = self::factory()->xprofile_group->create(); 565 566 $f = self::factory()->xprofile_field->create( array( 567 'field_group_id' => $group_ids[1], 568 ) ); 569 $field = new BP_XProfile_Field( $f ); 570 571 $args = array( 572 'hide_empty_groups' => true, 573 ); 574 575 // Prime cache. 576 $found = BP_XProfile_Group::get_group_ids( $args ); 577 $this->assertContains( $group_ids[1], $found ); 578 579 $field->delete(); 580 581 $found = BP_XProfile_Group::get_group_ids( $args ); 582 $this->assertNotContains( $group_ids[1], $found ); 583 } 584 585 /** 586 * @group BP7435 587 * @group cache 588 */ 589 public function test_group_field_ids_query_cache() { 590 global $wpdb; 591 592 $group_id = self::factory()->xprofile_group->create(); 593 594 $f = self::factory()->xprofile_field->create( array( 595 'field_group_id' => $group_id, 596 ) ); 597 $field = new BP_XProfile_Field( $f ); 598 599 // Prime cache. 600 $found = BP_XProfile_Group::get_group_field_ids( array( $group_id ) ); 601 $this->assertContains( $f, $found ); 602 603 $num_queries = $wpdb->num_queries; 604 605 $found = BP_XProfile_Group::get_group_field_ids( array( $group_id ) ); 606 $this->assertContains( $f, $found ); 607 $this->assertSame( $num_queries, $wpdb->num_queries ); 608 } 609 610 /** 611 * @group BP7435 612 * @group cache 613 */ 614 public function test_group_field_ids_query_cache_should_be_busted_on_field_save() { 615 global $wpdb; 616 617 $group_id = self::factory()->xprofile_group->create(); 618 619 $f = self::factory()->xprofile_field->create( array( 620 'field_group_id' => $group_id, 621 ) ); 622 $field = new BP_XProfile_Field( $f ); 623 624 // Prime cache. 625 $found = BP_XProfile_Group::get_group_field_ids( array( $group_id ) ); 626 $this->assertContains( $f, $found ); 627 628 $field->save(); 629 $num_queries = $wpdb->num_queries; 630 631 $found = BP_XProfile_Group::get_group_field_ids( array( $group_id ) ); 632 $this->assertContains( $f, $found ); 633 $this->assertNotSame( $num_queries, $wpdb->num_queries ); 634 } 635 636 /** 637 * @group BP7435 638 * @group cache 639 */ 640 public function test_group_field_ids_query_cache_should_be_busted_on_field_delete() { 641 $group_id = self::factory()->xprofile_group->create(); 642 643 $f = self::factory()->xprofile_field->create( array( 644 'field_group_id' => $group_id, 645 ) ); 646 $field = new BP_XProfile_Field( $f ); 647 648 // Prime cache. 649 $found = BP_XProfile_Group::get_group_field_ids( array( $group_id ) ); 650 $this->assertContains( $f, $found ); 651 652 $field->delete(); 653 654 $found = BP_XProfile_Group::get_group_field_ids( array( $group_id ) ); 655 $this->assertNotContains( $f, $found ); 656 } 444 657 }