Skip to:
Content

BuddyPress.org

Changeset 10198


Ignore:
Timestamp:
10/07/2015 02:30:31 PM (11 years ago)
Author:
boonebgorges
Message:

Introduce cache support for xprofile fields.

xprofile_get_field() will now look in the cache before returning a
BP_XProfile_Field object (via the new BP_XProfile_Field::get_instance()),
and will populate the cache if necessary. It's strongly recommended to use
xprofile_get_field() when fetching individual existing fields, instead of
creating new BP_XProfile_Field objects directly.

BP_XProfile_Group::get() now leverages the field cache too. Instead of a
SELECT * query, it fetches a list of matching field IDs SELECT id, and
populates the full field objects from the cache, if available. The fields
property of BP_XProfile_Group objects is now an array of BP_XProfile_Field
objects, not stdClass. See #6358.

Props boonebgorges, r-a-y.
See #6638.

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bp-xprofile/bp-xprofile-cache.php

    r10163 r10198  
    284284add_action( 'update_option_bp-xprofile-fullname-field-name', 'xprofile_clear_fullname_field_id_cache' );
    285285
     286/**
     287 * Clear a field's caches.
     288 *
     289 * @since 2.4.0
     290 *
     291 * @param int|BP_XProfile_Field A field ID or a field object.
     292 * @param bool False on failure.
     293 */
     294function bp_xprofile_clear_field_cache( $field ) {
     295        if ( is_numeric( $field ) ) {
     296                $field_id = (int) $field;
     297        } elseif ( $field instanceof BP_XProfile_Field ) {
     298                $field_id = (int) $field->id;
     299        }
     300
     301        if ( ! isset( $field_id ) ) {
     302                return false;
     303        }
     304
     305        wp_cache_delete( $field_id, 'bp_xprofile_fields' );
     306        wp_cache_delete( $field_id, 'xprofile_meta' );
     307}
     308add_action( 'xprofile_field_after_save', 'bp_xprofile_clear_field_cache' );
     309
    286310// List actions to clear super cached pages on, if super cache is installed.
    287311add_action( 'xprofile_updated_profile', 'bp_core_clear_cache' );
  • trunk/src/bp-xprofile/bp-xprofile-functions.php

    r10163 r10198  
    276276}
    277277
    278 function xprofile_get_field( $field_id ) {
    279         return new BP_XProfile_Field( $field_id );
     278/**
     279 * Get a profile field object.
     280 *
     281 * @param int|object $field ID of the field or object representing field data.
     282 * @return BP_XProfile_Field|null Field object if found, otherwise null.
     283 */
     284function xprofile_get_field( $field ) {
     285        if ( $field instanceof BP_XProfile_Field ) {
     286                $_field = $field;
     287        } elseif ( is_object( $field ) ) {
     288                $_field = new BP_XProfile_Field();
     289                $_field->fill_data( $field );
     290        } else {
     291                $_field = BP_XProfile_Field::get_instance( $field );
     292        }
     293
     294        if ( ! $_field ) {
     295                return null;
     296        }
     297
     298        return $_field;
    280299}
    281300
  • trunk/src/bp-xprofile/bp-xprofile-loader.php

    r10163 r10198  
    394394                        'bp_xprofile',
    395395                        'bp_xprofile_data',
     396                        'bp_xprofile_fields',
    396397                        'bp_xprofile_groups',
    397398                        'xprofile_meta'
  • trunk/src/bp-xprofile/classes/class-bp-xprofile-field.php

    r10195 r10198  
    212212                $field = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE id = %d", $id ) );
    213213
    214                 if ( ! empty( $field ) ) {
    215                         $this->id                = $field->id;
    216                         $this->group_id          = $field->group_id;
    217                         $this->parent_id         = $field->parent_id;
    218                         $this->type              = $field->type;
    219                         $this->name              = stripslashes( $field->name );
    220                         $this->description       = stripslashes( $field->description );
    221                         $this->is_required       = $field->is_required;
    222                         $this->can_delete        = $field->can_delete;
    223                         $this->field_order       = $field->field_order;
    224                         $this->option_order      = $field->option_order;
    225                         $this->order_by          = $field->order_by;
    226                         $this->is_default_option = $field->is_default_option;
    227 
    228                         // Create the field type and store a reference back to this object.
    229                         $this->type_obj            = bp_xprofile_create_field_type( $field->type );
    230                         $this->type_obj->field_obj = $this;
    231 
    232                         if ( ! empty( $get_data ) && ! empty( $user_id ) ) {
    233                                 $this->data = $this->get_field_data( $user_id );
    234                         }
    235                 }
     214                $this->fill_data( $field );
     215
     216                if ( ! empty( $get_data ) && ! empty( $user_id ) ) {
     217                        $this->data = $this->get_field_data( $user_id );
     218                }
     219        }
     220
     221        /**
     222         * Retrieve a `BP_XProfile_Field` instance.
     223         *
     224         * @static
     225         *
     226         * @param int $field_id ID of the field.
     227         * @return BP_XProfile_Field|false Field object if found, otherwise false.
     228         */
     229        public static function get_instance( $field_id ) {
     230                global $wpdb;
     231
     232                $field_id = (int) $field_id;
     233                if ( ! $field_id ) {
     234                        return false;
     235                }
     236
     237                $field = wp_cache_get( $field_id, 'bp_xprofile_fields' );
     238                if ( false === $field ) {
     239                        $bp = buddypress();
     240
     241                        $field = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_fields} WHERE id = %d", $field_id ) );
     242
     243                        wp_cache_add( $field->id, $field, 'bp_xprofile_fields' );
     244
     245                        if ( ! $field ) {
     246                                return false;
     247                        }
     248                }
     249
     250                $_field = new BP_XProfile_Field();
     251                $_field->fill_data( $field );
     252
     253                return $_field;
     254        }
     255
     256        /**
     257         * Fill object vars based on data passed to the method.
     258         *
     259         * @since 2.4.0
     260         *
     261         * @param array|object $args Array or object representing the `BP_XProfile_Field` properties.
     262         *                           Generally, this is a row from the fields database table.
     263         */
     264        public function fill_data( $args ) {
     265                if ( is_object( $args ) ) {
     266                        $args = (array) $args;
     267                }
     268
     269                foreach ( $args as $k => $v ) {
     270                        if ( 'name' === $k || 'description' === $k ) {
     271                                $v = stripslashes( $v );
     272                        }
     273                        $this->{$k} = $v;
     274                }
     275
     276                // Create the field type and store a reference back to this object.
     277                $this->type_obj            = bp_xprofile_create_field_type( $this->type );
     278                $this->type_obj->field_obj = $this;;
    236279        }
    237280
  • trunk/src/bp-xprofile/classes/class-bp-xprofile-group.php

    r10176 r10198  
    370370
    371371                // Fetch the fields.
    372                 $fields = $wpdb->get_results( "SELECT id, name, description, type, group_id, is_required 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" );
    373 
    374                 $field_ids = wp_list_pluck( $fields, 'id' );
     372                $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" );
     373
     374                // Bail if no fields.
     375                if ( empty( $field_ids ) ) {
     376                        return $groups;
     377                }
     378
     379                $field_ids = array_map( 'intval', $field_ids );
     380
     381                // Prime the field cache.
     382                $uncached_field_ids = bp_get_non_cached_ids( $field_ids, 'bp_xprofile_fields' );
     383                if ( ! empty( $uncached_field_ids ) ) {
     384                        $_uncached_field_ids = implode( ',', array_map( 'intval', $uncached_field_ids ) );
     385                        $uncached_fields = $wpdb->get_results( "SELECT * FROM {$bp->profile->table_name_fields} WHERE id IN ({$_uncached_field_ids})" );
     386                        foreach ( $uncached_fields as $uncached_field ) {
     387                                $fid = intval( $uncached_field->id );
     388                                wp_cache_set( $fid, $uncached_field, 'bp_xprofile_fields' );
     389                        }
     390                }
     391
     392                // Pull field objects from the cache.
     393                $fields = array();
     394                foreach ( $field_ids as $field_id ) {
     395                        $fields[] = xprofile_get_field( $field_id );
     396                }
    375397
    376398                // Store field IDs for meta cache priming.
    377399                $object_ids['field'] = $field_ids;
    378 
    379                 // Bail if no fields.
    380                 if ( empty( $fields ) ) {
    381                         return $groups;
    382                 }
    383400
    384401                // Maybe fetch field data.
  • trunk/tests/phpunit/testcases/xprofile/cache.php

    r10004 r10198  
    145145                $this->assertFalse( wp_cache_get( $d->id, 'xprofile_data_meta' ) );
    146146        }
     147
     148        /**
     149         * @ticket BP6638
     150         */
     151        public function test_field_cache_should_be_invalidated_on_save() {
     152                $g = $this->factory->xprofile_group->create();
     153                $f = $this->factory->xprofile_field->create( array(
     154                        'field_group_id' => $g,
     155                        'name' => 'Foo',
     156                ) );
     157
     158                $field = xprofile_get_field( $f );
     159                $this->assertSame( 'Foo', $field->name );
     160
     161                $field->name = 'Bar';
     162                $this->assertNotEmpty( $field->save() );
     163
     164                $field_2 = xprofile_get_field( $f );
     165                $this->assertSame( 'Bar', $field_2->name );
     166        }
    147167}
  • trunk/tests/phpunit/testcases/xprofile/functions.php

    r10143 r10198  
    869869                $this->assertEquals( array( 1, $g1, $g3, $g2 ), wp_list_pluck( $field_groups, 'id' ) );
    870870        }
     871
     872        /**
     873         * @ticket BP6638
     874         */
     875        public function test_xprofile_get_field_should_return_bp_xprofile_field_object() {
     876                global $wpdb;
     877
     878                $g = $this->factory->xprofile_group->create();
     879                $f = $this->factory->xprofile_field->create( array(
     880                        'field_group_id' => $g,
     881                        'type' => 'selectbox',
     882                        'name' => 'Foo',
     883                ) );
     884
     885                $field = xprofile_get_field( $f );
     886
     887                $this->assertTrue( $field instanceof BP_XProfile_Field );
     888        }
     889
     890        /**
     891         * @ticket BP6638
     892         * @group cache
     893         */
     894        public function test_xprofile_get_field_should_prime_field_cache() {
     895                global $wpdb;
     896
     897                $g = $this->factory->xprofile_group->create();
     898                $f = $this->factory->xprofile_field->create( array(
     899                        'field_group_id' => $g,
     900                        'type' => 'selectbox',
     901                        'name' => 'Foo',
     902                ) );
     903
     904                $num_queries = $wpdb->num_queries;
     905
     906                // Prime the cache.
     907                $field_1 = xprofile_get_field( $f );
     908                $num_queries++;
     909                $this->assertSame( $num_queries, $wpdb->num_queries );
     910
     911                // No more queries.
     912                $field_2 = xprofile_get_field( $f );
     913                $this->assertEquals( $field_1, $field_2 );
     914                $this->assertSame( $num_queries, $wpdb->num_queries );
     915        }
    871916}
Note: See TracChangeset for help on using the changeset viewer.