Skip to:
Content

BuddyPress.org

Changeset 10198


Ignore:
Timestamp:
10/07/2015 02:30:31 PM (9 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.