Skip to:
Content

BuddyPress.org

Ticket #7435: 7435.diff

File 7435.diff, 17.4 KB (added by boonebgorges, 3 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() { 
    287287}
    288288add_action( 'xprofile_field_before_save', 'bp_xprofile_reset_fields_by_name_cache_incrementor' );
    289289
     290/**
     291 * Resets all incremented bp_xprofile_groups caches.
     292 *
     293 * @since 4.0.0
     294 */
     295function bp_xprofile_reset_groups_cache_incrementor() {
     296        bp_core_reset_incrementor( 'bp_xprofile_groups' );
     297}
     298add_action( 'xprofile_group_after_delete', 'bp_xprofile_reset_groups_cache_incrementor' );
     299add_action( 'xprofile_group_after_save', 'bp_xprofile_reset_groups_cache_incrementor' );
     300add_action( 'xprofile_field_after_delete', 'bp_xprofile_reset_groups_cache_incrementor' );
     301add_action( 'xprofile_field_after_save', 'bp_xprofile_reset_groups_cache_incrementor' );
     302
    290303// List actions to clear super cached pages on, if super cache is installed.
    291304add_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 { 
    977977                $sql        = $wpdb->prepare( "UPDATE {$table_name} SET field_order = %d, group_id = %d WHERE id = %d", $position, $field_group_id, $field_id );
    978978                $parent     = $wpdb->query( $sql );
    979979
     980                $retval = false;
     981
    980982                // Update $field_id with new $position and $field_group_id.
    981983                if ( ! empty( $parent ) && ! is_wp_error( $parent ) ) {
    982984
    class BP_XProfile_Field { 
    984986                        $sql = $wpdb->prepare( "UPDATE {$table_name} SET group_id = %d WHERE parent_id = %d", $field_group_id, $field_id );
    985987                        $wpdb->query( $sql );
    986988
    987                         // Invalidate profile field cache.
     989                        // Invalidate profile field and group query cache.
    988990                        wp_cache_delete( $field_id, 'bp_xprofile_fields' );
    989991
    990                         return $parent;
     992                        $retval = $parent;
    991993                }
    992994
    993                 return false;
     995                bp_core_reset_incrementor( 'bp_xprofile_groups' );
     996
     997                return $retval;
    994998        }
    995999
    9961000        /**
  • 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 { 
    288288                        'data'  => array(),
    289289                );
    290290
    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 
    301291                $bp = buddypress();
    302292
    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 );
    309294
    310295                // Get all group data.
    311296                $groups = self::get_group_data( $group_ids );
    class BP_XProfile_Group { 
    326311                        return $groups;
    327312                }
    328313
    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 );
    375315
    376316                foreach( $groups as $group ) {
    377317                        $group->fields = array();
    class BP_XProfile_Group { 
    498438                return $groups;
    499439        }
    500440
     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
    501587        /**
    502588         * Get data about a set of groups, based on IDs.
    503589         *
    class BP_XProfile_Group { 
    613699                        return false;
    614700                }
    615701
    616                 // Purge profile field group cache.
     702                // Purge profile field group and group query caches.
    617703                wp_cache_delete( 'all', 'bp_xprofile_groups' );
     704                bp_core_reset_incrementor( 'bp_xprofile_groups' );
    618705
    619706                $bp = buddypress();
    620707
  • 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 { 
    441441
    442442                $this->assertSame( "Test ' Name", $e1->name );
    443443        }
     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        }
    444657}