Skip to:
Content

BuddyPress.org

Changeset 7862


Ignore:
Timestamp:
02/13/2014 03:50:39 AM (6 years ago)
Author:
boonebgorges
Message:

Migrate xprofilemeta functions to the WP metadata API

The case of XProfile metadata is complex, because xprofile groups, fields, and
data all store their metadata in a single table, differentiated by object_type.
This complication requires additional filters on WP's core metadata queries.

See #4551

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/bp-xprofile/bp-xprofile-filters.php

    r7812 r7862  
    262262}
    263263add_filter( 'bp_user_query_populate_extras', 'bp_xprofile_filter_user_query_populate_extras', 2, 2 );
     264
     265/**
     266 * Filter meta queries to modify for the xprofile data schema.
     267 *
     268 * @since BuddyPress (2.0.0)
     269 *
     270 * @access private Do not use.
     271 *
     272 * @param string $q SQL query.
     273 * @return string
     274 */
     275function bp_xprofile_filter_meta_query( $q ) {
     276    global $wpdb;
     277
     278    // Get the first word of the command
     279    preg_match( '/^(\S+)/', $q, $first_word_matches );
     280
     281    if ( empty( $first_word_matches[0] ) ) {
     282        return $q;
     283    }
     284
     285    // Get the field type
     286    preg_match( '/xprofile_(group|field|data)_id/', $q, $matches );
     287
     288    if ( empty( $matches[0] ) || empty( $matches[1] ) ) {
     289        return $q;
     290    }
     291
     292    switch ( $first_word_matches[0] ) {
     293
     294        /**
     295         * SELECT:
     296         * - replace 'xprofile_{fieldtype}_id' with 'object_id'
     297         * - ensure that 'object_id' is aliased to 'xprofile_{fieldtype}_id',
     298         *   because update_meta_cache() needs the column name to parse
     299         *   the query results
     300         * - append the 'object type' WHERE clause
     301         */
     302        case 'SELECT' :
     303            $q = str_replace(
     304                array(
     305                    $matches[0],
     306                    'SELECT object_id',
     307                    'WHERE ',
     308                ),
     309                array(
     310                    'object_id',
     311                    'SELECT object_id AS ' . $matches[0],
     312                    $wpdb->prepare( 'WHERE object_type = %s AND ', $matches[1] ),
     313                ),
     314                $q
     315            );
     316            break;
     317
     318        /**
     319         * UPDATE and DELETE:
     320         * - replace 'xprofile_{fieldtype}_id' with 'object_id'
     321         * - append the 'object type' WHERE clause
     322         */
     323        case 'UPDATE' :
     324        case 'DELETE' :
     325            $q = str_replace(
     326                array(
     327                    $matches[0],
     328                    'WHERE ',
     329                ),
     330                array(
     331                    'object_id',
     332                    $wpdb->prepare( 'WHERE object_type = %s AND ', $matches[1] ),
     333                ),
     334                $q
     335            );
     336            break;
     337
     338        /**
     339         * UPDATE and DELETE:
     340         * - replace 'xprofile_{fieldtype}_id' with 'object_id'
     341         * - ensure that the object_type field gets filled in
     342         */
     343        case 'INSERT' :
     344            $q = str_replace(
     345                array(
     346                    '`' . $matches[0] . '`',
     347                    'VALUES (',
     348                ),
     349                array(
     350                    '`object_type`,`object_id`',
     351                    $wpdb->prepare( "VALUES (%s,", $matches[1] ),
     352                ),
     353                $q
     354            );
     355            break;
     356    }
     357
     358    return $q;
     359}
  • trunk/bp-xprofile/bp-xprofile-functions.php

    r7836 r7862  
    530530/*** XProfile Meta ****************************************************/
    531531
     532/**
     533 * Delete a piece of xprofile metadata.
     534 *
     535 * @param int $object_id ID of the object the metadata belongs to.
     536 * @param string $object_type Type of object. 'group', 'field', or 'data'.
     537 * @param string $meta_key Key of the metadata being deleted. If omitted, all
     538 *        metadata for the object will be deleted.
     539 * @param mixed $meta_value Optional. If provided, only metadata that matches
     540 *        the value will be permitted.
     541 * @return bool True on success, false on failure.
     542 */
    532543function bp_xprofile_delete_meta( $object_id, $object_type, $meta_key = false, $meta_value = false ) {
    533     global $wpdb, $bp;
    534 
    535     $object_id = (int) $object_id;
    536 
    537     if ( !$object_id )
    538         return false;
    539 
    540     if ( !isset( $object_type ) )
    541         return false;
    542 
    543     if ( !in_array( $object_type, array( 'group', 'field', 'data' ) ) )
    544         return false;
    545 
     544    global $wpdb;
     545
     546    // Legacy - no empty object id
     547    if ( empty( $object_id ) ) {
     548        return false;
     549    }
     550
     551    // Legacy - sanitize object type
     552    if ( ! in_array( $object_type, array( 'group', 'field', 'data' ) ) ) {
     553        return false;
     554    }
     555
     556    // Legacy - if no meta_key is passed, delete all for the item
     557    if ( empty( $meta_key ) ) {
     558        $table_key  = 'xprofile_' . $object_type . 'meta';
     559        $table_name = $wpdb->{$table_key};
     560        $keys = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$table_name} WHERE object_type = %s AND object_id = %d", $object_type, $object_id ) );
     561    } else {
     562        $keys = array( $meta_key );
     563    }
     564
     565    // Legacy - trim meta_value
     566    $meta_value = trim( $meta_value );
     567
     568    add_filter( 'query', 'bp_filter_metaid_column_name' );
     569    add_filter( 'query', 'bp_xprofile_filter_meta_query' );
     570
     571    foreach ( $keys as $key ) {
     572        $retval = delete_metadata( 'xprofile_' . $object_type, $object_id, $key, $meta_value );
     573    }
     574
     575    remove_filter( 'query', 'bp_xprofile_filter_meta_query' );
     576    remove_filter( 'query', 'bp_filter_metaid_column_name' );
     577
     578    return $retval;
     579}
     580
     581/**
     582 * Get a piece of xprofile metadata.
     583 *
     584 * @param int $object_id ID of the object the metadata belongs to.
     585 * @param string $object_type Type of object. 'group', 'field', or 'data'.
     586 * @param string $meta_key Key of the metadata being fetched. If omitted, all
     587 *        metadata for the object will be retrieved.
     588 * @return mixed Meta value if found. False on failure.
     589 */
     590function bp_xprofile_get_meta( $object_id, $object_type, $meta_key = '') {
     591    // Legacy - sanitize object type
     592    if ( ! in_array( $object_type, array( 'group', 'field', 'data' ) ) ) {
     593        return false;
     594    }
     595
     596    add_filter( 'query', 'bp_filter_metaid_column_name' );
     597    add_filter( 'query', 'bp_xprofile_filter_meta_query' );
     598    $retval = get_metadata( 'xprofile_' . $object_type, $object_id, $meta_key, true );
     599    remove_filter( 'query', 'bp_filter_metaid_column_name' );
     600    remove_filter( 'query', 'bp_xprofile_filter_meta_query' );
     601
     602    // Legacy - if no meta_key is provided, return just the located
     603    // values (not a structured array)
     604    if ( empty( $meta_key ) && ! empty( $retval ) ) {
     605        $values = array();
     606        foreach ( $retval as $v ) {
     607            $values[] = array_pop( $v );
     608        }
     609
     610        $retval = $values;
     611    }
     612
     613    return $retval;
     614}
     615
     616/**
     617 * Update a piece of xprofile metadata.
     618 *
     619 * @param int $object_id ID of the object the metadata belongs to.
     620 * @param string $object_type Type of object. 'group', 'field', or 'data'.
     621 * @param string $meta_key Key of the metadata being updated.
     622 * @param mixed $meta_value Value of the metadata being updated.
     623 * @return bool True on success, false on failure.
     624 */
     625function bp_xprofile_update_meta( $object_id, $object_type, $meta_key, $meta_value ) {
     626
     627    // Legacy - sanitize meta_key
    546628    $meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
    547629
    548     if ( is_array( $meta_value ) || is_object( $meta_value ) ) {
    549         $meta_value = serialize( $meta_value );
    550     }
    551 
    552     $meta_value = trim( $meta_value );
    553 
    554     if ( empty( $meta_key ) ) {
    555         $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s", $object_id, $object_type ) );
    556     } elseif ( !empty( $meta_value ) ) {
    557         $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s AND meta_key = %s AND meta_value = %s", $object_id, $object_type, $meta_key, $meta_value ) );
    558     } else {
    559         $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s AND meta_key = %s", $object_id, $object_type, $meta_key ) );
    560     }
    561 
    562     // Delete the cached object
    563     wp_cache_delete( 'bp_xprofile_meta_' . $object_type . '_' . $object_id . '_' . $meta_key, 'bp' );
    564 
    565     return true;
    566 }
    567 
    568 function bp_xprofile_get_meta( $object_id, $object_type, $meta_key = '') {
    569     global $wpdb, $bp;
    570 
    571     $object_id = (int) $object_id;
    572 
    573     if ( !$object_id )
    574         return false;
    575 
    576     if ( !isset( $object_type ) )
    577         return false;
    578 
    579     if ( !in_array( $object_type, array( 'group', 'field', 'data' ) ) )
    580         return false;
    581 
    582     if ( !empty( $meta_key ) ) {
    583         $meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
    584 
    585         if ( !$metas = wp_cache_get( 'bp_xprofile_meta_' . $object_type . '_' . $object_id . '_' . $meta_key, 'bp' ) ) {
    586             $metas = $wpdb->get_col( $wpdb->prepare( "SELECT meta_value FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s AND meta_key = %s", $object_id, $object_type, $meta_key ) );
    587             wp_cache_set( 'bp_xprofile_meta_' . $object_type . '_' . $object_id . '_' . $meta_key, $metas, 'bp' );
    588         }
    589     } else {
    590         $metas = $wpdb->get_col( $wpdb->prepare( "SELECT meta_value FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s", $object_id, $object_type ) );
    591     }
    592 
    593     if ( empty( $metas ) ) {
    594         if ( empty( $meta_key ) ) {
    595             return array();
    596         } else {
    597             return '';
    598         }
    599     }
    600 
    601     $metas = array_map( 'maybe_unserialize', (array) $metas );
    602 
    603     if ( 1 == count( $metas ) )
    604         return $metas[0];
    605     else
    606         return $metas;
    607 }
    608 
    609 function bp_xprofile_update_meta( $object_id, $object_type, $meta_key, $meta_value ) {
    610     global $wpdb, $bp;
    611 
    612     $object_id = (int) $object_id;
    613 
    614     if ( empty( $object_id ) )
    615         return false;
    616 
    617     if ( !isset( $object_type ) )
    618         return false;
    619 
    620     if ( !in_array( $object_type, array( 'group', 'field', 'data' ) ) )
    621         return false;
    622 
    623     $meta_key = preg_replace( '|[^a-z0-9_]|i', '', $meta_key );
    624 
    625     if ( is_string( $meta_value ) ) {
    626         $meta_value = stripslashes( $meta_value );
    627     }
    628 
    629     $meta_value = maybe_serialize( $meta_value );
    630 
    631     if ( empty( $meta_value ) )
    632         return bp_xprofile_delete_meta( $object_id, $object_type, $meta_key );
    633 
    634     $cur = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->profile->table_name_meta} WHERE object_id = %d AND object_type = %s AND meta_key = %s", $object_id, $object_type, $meta_key ) );
    635 
    636     if ( empty( $cur ) )
    637         $wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->profile->table_name_meta} ( object_id, object_type, meta_key, meta_value ) VALUES ( %d, %s, %s, %s )", $object_id, $object_type,  $meta_key, $meta_value ) );
    638     else if ( $cur->meta_value != $meta_value )
    639         $wpdb->query( $wpdb->prepare( "UPDATE {$bp->profile->table_name_meta} SET meta_value = %s WHERE object_id = %d AND object_type = %s AND meta_key = %s", $meta_value, $object_id, $object_type, $meta_key ) );
    640     else
    641         return false;
    642 
    643     // Update the cached object and recache
    644     wp_cache_set( 'bp_xprofile_meta_' . $object_type . '_' . $object_id . '_' . $meta_key, $meta_value, 'bp' );
    645 
    646     return true;
     630    add_filter( 'query', 'bp_filter_metaid_column_name' );
     631    add_filter( 'query', 'bp_xprofile_filter_meta_query' );
     632    $retval = update_metadata( 'xprofile_' . $object_type, $object_id, $meta_key, $meta_value );
     633    remove_filter( 'query', 'bp_xprofile_filter_meta_query' );
     634    remove_filter( 'query', 'bp_filter_metaid_column_name' );
     635
     636    // Legacy - if we fall through to add_metadata(), return true rather
     637    // than the integer meta_id
     638    if ( is_int( $retval ) ) {
     639        $retval = (bool) $retval;
     640    }
     641
     642    return $retval;
    647643}
    648644
  • trunk/bp-xprofile/bp-xprofile-loader.php

    r7756 r7862  
    139139        );
    140140
     141        $meta_tables = array(
     142            'xprofile_group' => $bp->table_prefix . 'bp_xprofile_meta',
     143            'xprofile_field' => $bp->table_prefix . 'bp_xprofile_meta',
     144            'xprofile_data'  => $bp->table_prefix . 'bp_xprofile_meta',
     145        );
     146
    141147        $globals = array(
    142148            'slug'                  => BP_XPROFILE_SLUG,
    143149            'has_directory'         => false,
    144150            'notification_callback' => 'xprofile_format_notifications',
    145             'global_tables'         => $global_tables
     151            'global_tables'         => $global_tables,
     152            'meta_tables'           => $meta_tables,
    146153        );
    147154
  • trunk/tests/testcases/xprofile/functions.php

    r7856 r7862  
    235235
    236236        // These will fail because of a caching bug
    237         //$this->assertEquals( '', bp_xprofile_get_meta( $g->id, 'group', 'foo' ) );
    238         //$this->assertEquals( '', bp_xprofile_get_meta( $g->id, 'group', 'foo2' ) );
     237        $this->assertEquals( '', bp_xprofile_get_meta( $g->id, 'group', 'foo' ) );
     238        $this->assertEquals( '', bp_xprofile_get_meta( $g->id, 'group', 'foo2' ) );
    239239    }
    240240
Note: See TracChangeset for help on using the changeset viewer.