Skip to:
Content

BuddyPress.org

Ticket #5451: 5451.diff

File 5451.diff, 14.9 KB (added by boonebgorges, 5 years ago)
  • src/bp-groups/classes/class-bp-groups-group.php

    diff --git src/bp-groups/classes/class-bp-groups-group.php src/bp-groups/classes/class-bp-groups-group.php
    index 1533c23..9aafce2 100644
    class BP_Groups_Group { 
    105105         * @since 1.6.0
    106106         * @var int
    107107         */
    108         public $total_member_count;
     108        protected $total_member_count;
    109109
    110110        /**
    111111         * Is the current user a member of this group?
    class BP_Groups_Group { 
    137137         * @since 1.2.0
    138138         * @var string
    139139         */
    140         public $last_activity;
     140        protected $last_activity;
    141141
    142142        /**
    143143         * If this is a private or hidden group, does the current user have access?
    class BP_Groups_Group { 
    242242                                }
    243243                        }
    244244
    245                         // Set up some specific group vars from meta. Excluded
    246                         // from the bp_groups cache because it's cached independently.
    247                         $this->last_activity      = groups_get_groupmeta( $this->id, 'last_activity' );
    248                         $this->total_member_count = (int) groups_get_groupmeta( $this->id, 'total_member_count' );
    249 
    250245                        // Set user-specific data.
    251246                        $user_id          = bp_loggedin_user_id();
    252247                        $this->is_member  = groups_is_user_member( $user_id, $this->id );
    class BP_Groups_Group { 
    429424                return true;
    430425        }
    431426
     427        /**
     428         * Magic getter.
     429         *
     430         * @since 2.7.0
     431         *
     432         * @param string $key Property name.
     433         * @return mixed
     434         */
     435        public function __get( $key ) {
     436                switch ( $key ) {
     437                        case 'last_activity' :
     438                                return groups_get_groupmeta( $this->id, 'last_activity' );
     439
     440                        case 'total_member_count' :
     441                                return (int) groups_get_groupmeta( $this->id, 'total_member_count' );
     442
     443                        default :
     444                        break;
     445                }
     446        }
     447
     448        /**
     449         * Magic issetter.
     450         *
     451         * Used to maintain backward compatibility for properties that are now
     452         * accessible only via magic method.
     453         *
     454         * @since 2.7.0
     455         *
     456         * @param string $key Property name.
     457         * @return bool
     458         */
     459        public function __isset( $key ) {
     460                switch ( $key ) {
     461                        case 'last_activity' :
     462                        case 'total_member_count' :
     463                                return true;
     464
     465                        default :
     466                                return false;
     467                }
     468        }
     469
    432470        /** Static Methods ****************************************************/
    433471
    434472        /**
    class BP_Groups_Group { 
    777815
    778816                $bp = buddypress();
    779817
    780                 $sql       = array();
    781                 $total_sql = array();
    782 
    783                 $sql['select'] = "SELECT DISTINCT g.id, g.*, gm1.meta_value AS total_member_count, gm2.meta_value AS last_activity";
    784                 $sql['from']   = " FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2,";
    785 
    786                 if ( ! empty( $r['user_id'] ) ) {
    787                         $sql['members_from'] = " {$bp->groups->table_name_members} m,";
    788                 }
     818                $sql = array(
     819                        'select' => '',
     820                        'from' => '',
     821                        'where' => '',
     822                        'orderby' => '',
     823                        'pagination' => '',
     824                );
    789825
    790                 $sql['group_from'] = " {$bp->groups->table_name} g WHERE";
     826                $sql['select'] = "SELECT DISTINCT g.id";
     827                $sql['from']   = "{$bp->groups->table_name} g JOIN {$bp->groups->table_name_groupmeta} gm_last_activity on ( g.id = gm_last_activity.group_id )";
    791828
    792829                if ( ! empty( $r['user_id'] ) ) {
    793                         $sql['user_where'] = " g.id = m.group_id AND";
     830                        $sql['from'] .= " JOIN {$bp->groups->table_name_members} m ON ( g.id = m.group_id )";
    794831                }
    795832
    796                 $sql['where'] = " g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count'";
     833                $where_conditions = array();
     834                $where_conditions['last_activity'] = "gm_last_activity.meta_key = 'last_activity'";
    797835
    798836                if ( empty( $r['show_hidden'] ) ) {
    799                         $sql['hidden'] = " AND g.status != 'hidden'";
     837                        $where_conditions['hidden'] = "g.status != 'hidden'";
    800838                }
    801839
    802840                if ( ! empty( $r['search_terms'] ) ) {
    803841                        $search_terms_like = '%' . bp_esc_like( $r['search_terms'] ) . '%';
    804                         $sql['search'] = $wpdb->prepare( " AND ( g.name LIKE %s OR g.description LIKE %s )", $search_terms_like, $search_terms_like );
     842                        $where_conditions['search'] = $wpdb->prepare( "( g.name LIKE %s OR g.description LIKE %s )", $search_terms_like, $search_terms_like );
    805843                }
    806844
    807845                $meta_query_sql = self::get_meta_query_sql( $r['meta_query'] );
    class BP_Groups_Group { 
    811849                }
    812850
    813851                if ( ! empty( $meta_query_sql['where'] ) ) {
    814                         $sql['meta'] = $meta_query_sql['where'];
     852                        $where_conditions['meta'] = $meta_query_sql['where'];
    815853                }
    816854
    817855                // Only use 'group_type__in', if 'group_type' is not set.
    class BP_Groups_Group { 
    829867                }
    830868
    831869                if ( ! empty( $group_type_clause ) ) {
    832                         $sql['group_type'] = $group_type_clause;
     870                        $where_conditions['group_type'] = $group_type_clause;
    833871                }
    834872
    835873                if ( ! empty( $r['user_id'] ) ) {
    836                         $sql['user'] = $wpdb->prepare( " AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id'] );
     874                        $where_conditions['user'] = $wpdb->prepare( "m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id'] );
    837875                }
    838876
    839877                if ( ! empty( $r['include'] ) ) {
    840878                        $include        = implode( ',', wp_parse_id_list( $r['include'] ) );
    841                         $sql['include'] = " AND g.id IN ({$include})";
     879                        $where_conditions['include'] = "g.id IN ({$include})";
    842880                }
    843881
    844882                if ( ! empty( $r['exclude'] ) ) {
    845883                        $exclude        = implode( ',', wp_parse_id_list( $r['exclude'] ) );
    846                         $sql['exclude'] = " AND g.id NOT IN ({$exclude})";
     884                        $where_conditions['exclude'] = "g.id NOT IN ({$exclude})";
    847885                }
    848886
    849887                /* Order/orderby ********************************************/
    class BP_Groups_Group { 
    877915                        }
    878916                }
    879917
     918                // Ordering by 'total_member_count' requires another table join.
     919                if ( 'total_member_count' === $orderby ) {
     920                        $sql['from'] .= " JOIN {$bp->groups->table_name_groupmeta} gm_total_member_count ON ( g.id = gm_total_member_count.group_id )";
     921                        $where_conditions['total_member_count'] = "gm_total_member_count.meta_key = 'total_member_count'";
     922                }
     923
    880924                // Sanitize 'order'.
    881925                $order = bp_esc_sql_order( $order );
    882926
    class BP_Groups_Group { 
    893937
    894938                // Random order is a special case.
    895939                if ( 'rand()' === $orderby ) {
    896                         $sql[] = "ORDER BY rand()";
     940                        $sql['orderby'] = "ORDER BY rand()";
    897941                } else {
    898                         $sql[] = "ORDER BY {$orderby} {$order}";
     942                        $sql['orderby'] = "ORDER BY {$orderby} {$order}";
    899943                }
    900944
    901945                if ( ! empty( $r['per_page'] ) && ! empty( $r['page'] ) && $r['per_page'] != -1 ) {
    902946                        $sql['pagination'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $r['page'] - 1 ) * $r['per_page']), intval( $r['per_page'] ) );
    903947                }
    904948
     949                if ( ! empty( $where_conditions ) ) {
     950                        $sql['where'] = implode( ' AND ', $where_conditions );
     951                }
     952
     953                $paged_groups_sql = "{$sql['select']} FROM {$sql['from']} WHERE {$sql['where']} {$sql['orderby']} {$sql['pagination']}";
     954
    905955                /**
    906956                 * Filters the pagination SQL statement.
    907957                 *
    class BP_Groups_Group { 
    911961                 * @param array  $sql   Array of SQL parts before concatenation.
    912962                 * @param array  $r     Array of parsed arguments for the get method.
    913963                 */
    914                 $paged_groups_sql = apply_filters( 'bp_groups_get_paged_groups_sql', join( ' ', (array) $sql ), $sql, $r );
    915                 $paged_groups     = $wpdb->get_results( $paged_groups_sql );
    916 
    917                 $total_sql['select'] = "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name} g, {$bp->groups->table_name_groupmeta} gm";
    918 
    919                 if ( ! empty( $r['user_id'] ) ) {
    920                         $total_sql['select'] .= ", {$bp->groups->table_name_members} m";
    921                 }
    922 
    923                 if ( ! empty( $sql['hidden'] ) ) {
    924                         $total_sql['where'][] = "g.status != 'hidden'";
    925                 }
    926 
    927                 if ( ! empty( $sql['search'] ) ) {
    928                         $total_sql['where'][] = $wpdb->prepare( "( g.name LIKE %s OR g.description LIKE %s )", $search_terms_like, $search_terms_like );
    929                 }
    930 
    931                 if ( ! empty( $r['user_id'] ) ) {
    932                         $total_sql['where'][] = $wpdb->prepare( "m.group_id = g.id AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id'] );
    933                 }
    934 
    935                 // Temporary implementation of meta_query for total count
    936                 // See #5099.
    937                 if ( ! empty( $meta_query_sql['where'] ) ) {
    938                         // Join the groupmeta table.
    939                         $total_sql['select'] .= ", ". substr( $meta_query_sql['join'], 0, -2 );
    940 
    941                         // Modify the meta_query clause from paged_sql for our syntax.
    942                         $meta_query_clause = preg_replace( '/^\s*AND/', '', $meta_query_sql['where'] );
    943                         $total_sql['where'][] = $meta_query_clause;
    944                 }
    945 
    946                 // Trim leading 'AND' to match `$total_sql` query style.
    947                 if ( ! empty( $group_type_clause ) ) {
    948                         $total_sql['where'][] = preg_replace( '/^\s*AND\s*/', '', $group_type_clause );
    949                 }
    950 
    951                 // Already escaped in the paginated results block.
    952                 if ( ! empty( $include ) ) {
    953                         $total_sql['where'][] = "g.id IN ({$include})";
     964                $paged_groups_sql = apply_filters( 'bp_groups_get_paged_groups_sql', $paged_groups_sql, $sql, $r );
     965                $paged_group_ids  = $wpdb->get_col( $paged_groups_sql );
     966
     967                $uncached_group_ids = bp_get_non_cached_ids( $paged_group_ids, 'bp_groups' );
     968                if ( $uncached_group_ids ) {
     969                        $group_ids_sql = implode( ',', array_map( 'intval', $uncached_group_ids ) );
     970                        $group_data_objects = $wpdb->get_results( "SELECT g.* FROM {$bp->groups->table_name} g WHERE g.id IN ({$group_ids_sql})" );
     971                        foreach ( $group_data_objects as $group_data_object ) {
     972                                wp_cache_set( $group_data_object->id, $group_data_object, 'bp_groups' );
     973                        }
    954974                }
    955975
    956                 // Already escaped in the paginated results block.
    957                 if ( ! empty( $exclude ) ) {
    958                         $total_sql['where'][] = "g.id NOT IN ({$exclude})";
     976                $paged_groups = array();
     977                foreach ( $paged_group_ids as $paged_group_id ) {
     978                        $paged_groups[] = new BP_Groups_Group( $paged_group_id );
    959979                }
    960980
    961                 $total_sql['where'][] = "g.id = gm.group_id";
    962                 $total_sql['where'][] = "gm.meta_key = 'last_activity'";
    963 
    964                 $t_sql = $total_sql['select'];
    965 
    966                 if ( ! empty( $total_sql['where'] ) ) {
    967                         $t_sql .= " WHERE " . join( ' AND ', (array) $total_sql['where'] );
    968                 }
     981                $total_groups_sql = "SELECT COUNT(DISTINCT g.id) FROM {$sql['from']} WHERE {$sql['where']}";
    969982
    970983                /**
    971984                 * Filters the SQL used to retrieve total group results.
    class BP_Groups_Group { 
    976989                 * @param array  $total_sql Array of SQL parts for the query.
    977990                 * @param array  $r         Array of parsed arguments for the get method.
    978991                 */
    979                 $total_groups_sql = apply_filters( 'bp_groups_get_total_groups_sql', $t_sql, $total_sql, $r );
     992                $total_groups_sql = apply_filters( 'bp_groups_get_total_groups_sql', $total_groups_sql, $sql, $r );
    980993                $total_groups     = (int) $wpdb->get_var( $total_groups_sql );
    981994
    982995                $group_ids = array();
    class BP_Groups_Group { 
    9961009
    9971010                // Set up integer properties needing casting.
    9981011                $int_props = array(
    999                         'id', 'creator_id', 'enable_forum', 'total_member_count',
     1012                        'id', 'creator_id', 'enable_forum'
    10001013                );
    10011014
    10021015                // Integer casting.
    class BP_Groups_Group { 
    10151028         * Get the SQL for the 'meta_query' param in BP_Activity_Activity::get()
    10161029         *
    10171030         * We use WP_Meta_Query to do the heavy lifting of parsing the
    1018          * meta_query array and creating the necessary SQL clauses. However,
    1019          * since BP_Activity_Activity::get() builds its SQL differently than
    1020          * WP_Query, we have to alter the return value (stripping the leading
    1021          * AND keyword from the 'where' clause).
     1031         * meta_query array and creating the necessary SQL clauses.
    10221032         *
    10231033         * @since 1.8.0
    10241034         *
    class BP_Groups_Group { 
    10421052                        $wpdb->groupmeta = buddypress()->groups->table_name_groupmeta;
    10431053
    10441054                        $meta_sql = $groups_meta_query->get_sql( 'group', 'g', 'id' );
    1045 
    1046                         // BP_Groups_Group::get uses the comma syntax for table
    1047                         // joins, which means that we have to do some regex to
    1048                         // convert the INNER JOIN and move the ON clause to a
    1049                         // WHERE condition
    1050                         //
    1051                         // @todo It may be better in the long run to refactor
    1052                         // the more general query syntax to accord better with
    1053                         // BP/WP convention.
    1054                         preg_match_all( '/JOIN (.+?) ON/', $meta_sql['join'], $matches_a );
    1055                         preg_match_all( '/ON \((.+?)\)/', $meta_sql['join'], $matches_b );
    1056 
    1057                         if ( ! empty( $matches_a[1] ) && ! empty( $matches_b[1] ) ) {
    1058                                 $sql_array['join']  = implode( ',', $matches_a[1] ) . ', ';
    1059                                 $sql_array['where'] = $meta_sql['where'] . ' AND ' . implode( ' AND ', $matches_b[1] );
    1060                         }
     1055                        $sql_array['join']  = $meta_sql['join'];
     1056                        $sql_array['where'] = self::strip_leading_and( $meta_sql['where'] );
    10611057                }
    10621058
    10631059                return $sql_array;
    class BP_Groups_Group { 
    11971193                                break;
    11981194
    11991195                        case 'last_activity' :
    1200                                 $order_by_term = 'last_activity';
     1196                                $order_by_term = 'gm_last_activity.meta_value';
    12011197                                break;
    12021198
    12031199                        case 'total_member_count' :
    1204                                 $order_by_term = 'CONVERT(gm1.meta_value, SIGNED)';
     1200                                $order_by_term = 'CONVERT(gm_total_member_count.meta_value, SIGNED)';
    12051201                                break;
    12061202
    12071203                        case 'name' :
    class BP_Groups_Group { 
    16661662
    16671663                // The no_results clauses are the same between IN and NOT IN.
    16681664                if ( false !== strpos( $sql_clauses['where'], '0 = 1' ) ) {
    1669                         $clause = $sql_clauses['where'];
     1665                        $clause = self::strip_leading_and( $sql_clauses['where'] );
    16701666
    16711667                // The tax_query clause generated for NOT IN can be used almost as-is.
    16721668                } elseif ( 'NOT IN' === $operator ) {
    1673                         $clause = $sql_clauses['where'];
     1669                        $clause = self::strip_leading_and( $sql_clauses['where'] );
    16741670
    16751671                // IN clauses must be converted to a subquery.
    16761672                } elseif ( preg_match( '/' . $wpdb->term_relationships . '\.term_taxonomy_id IN \([0-9, ]+\)/', $sql_clauses['where'], $matches ) ) {
    1677                         $clause = " AND g.id IN ( SELECT object_id FROM $wpdb->term_relationships WHERE {$matches[0]} )";
     1673                        $clause = " g.id IN ( SELECT object_id FROM $wpdb->term_relationships WHERE {$matches[0]} )";
    16781674                }
    16791675
    16801676                if ( $switched ) {
    class BP_Groups_Group { 
    16831679
    16841680                return $clause;
    16851681        }
     1682
     1683        /**
     1684         * Strips the leading AND and any surrounding whitespace from a string.
     1685         *
     1686         * Used here to normalize SQL fragments generated by `WP_Meta_Query` and
     1687         * other utility classes.
     1688         *
     1689         * @since 2.7.0
     1690         *
     1691         * @param string $s String.
     1692         * @return string
     1693         */
     1694        protected static function strip_leading_and( $s ) {
     1695                return preg_replace( '/^\s*AND\s*/', '', $s );
     1696        }
    16861697}
  • tests/phpunit/testcases/groups/class-bp-groups-group.php

    diff --git tests/phpunit/testcases/groups/class-bp-groups-group.php tests/phpunit/testcases/groups/class-bp-groups-group.php
    index d42959c..4e14e1b 100644
    class BP_Tests_BP_Groups_Group_TestCases extends BP_UnitTestCase { 
    563563         */
    564564        public function test_convert_orderby_to_order_by_term_last_activity() {
    565565                $c = new _BP_Groups_Group();
    566                 $this->assertEquals( 'last_activity', _BP_Groups_Group::_convert_orderby_to_order_by_term( 'last_activity' ) );
     566                $this->assertEquals( 'gm_last_activity.meta_value', _BP_Groups_Group::_convert_orderby_to_order_by_term( 'last_activity' ) );
    567567        }
    568568
    569569        /**
    class BP_Tests_BP_Groups_Group_TestCases extends BP_UnitTestCase { 
    571571         */
    572572        public function test_convert_orderby_to_order_by_term_total_member_count() {
    573573                $c = new _BP_Groups_Group();
    574                 $this->assertEquals( 'CONVERT(gm1.meta_value, SIGNED)', _BP_Groups_Group::_convert_orderby_to_order_by_term( 'total_member_count' ) );
     574                $this->assertEquals( 'CONVERT(gm_total_member_count.meta_value, SIGNED)', _BP_Groups_Group::_convert_orderby_to_order_by_term( 'total_member_count' ) );
    575575        }
    576576
    577577        /**