Skip to:
Content

BuddyPress.org


Ignore:
Timestamp:
09/19/2021 03:58:09 PM (3 years ago)
Author:
imath
Message:

Improve SQL performance when updating/deleting a list of notifications

Instead of looping into a list of notifications to run an update/delete query for each notification, update/delete a list of notifications using a single query. Use primarly this change for message thread notifications and bulk notification actions.

Mainly introduces 2 new static methods to BP_Notifications_Notification:

  • BP_Notifications_Notification::update_id_list() let you update a list of notifications using their notification IDs or component item IDs.
  • BP_Notifications_Notification::delete_id_list() let you delete a list of notifications using their notification IDs or component item IDs.

Props oztaser

Fixes #8426

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bp-notifications/classes/class-bp-notifications-notification.php

    r13108 r13112  
    912912
    913913    /**
     914     * Update notifications using a list of ids/items_ids.
     915     *
     916     * @since 10.0.0
     917     *
     918     * @param string $field The name of the db field of the items to update.
     919     *                      Possible values are `id` or `item_id`.
     920     * @param int[]  $items The list of items to update.
     921     * @param array  $data  Array of notification data to update.
     922     * @param array  $where The WHERE params to use to specify the item IDs to update.
     923     * @return int|false    The number of updated rows. False on error.
     924     */
     925    public static function update_id_list( $field, $items = array(), $data = array(), $where = array() ) {
     926        global $wpdb;
     927        $bp = buddypress();
     928
     929        $supported_fields = array( 'id', 'item_id' );
     930
     931        if ( false === in_array( $field, $supported_fields, true ) ) {
     932            return false;
     933        }
     934
     935        if ( ! is_array( $items ) || ! is_array( $data ) || ! is_array( $where ) ) {
     936            return false;
     937        }
     938
     939        $update_args = self::get_query_clauses( $data );
     940        $where_args  = self::get_query_clauses( $where );
     941
     942        $fields     = array();
     943        $conditions = array();
     944        $values     = array();
     945
     946        $_items       = implode( ',', wp_parse_id_list( $items ) );
     947        $conditions[] = "{$field} IN ({$_items})";
     948
     949        foreach ( $update_args['data'] as $field => $value ) {
     950            $index  = array_search( $field, array_keys( $update_args['data'] ) );
     951            $format = $update_args['format'][ $index ];
     952
     953            $fields[] = "{$field} = {$format}";
     954            $values[] = $value;
     955        }
     956
     957        foreach ( $where_args['data'] as $field => $value ) {
     958            $index  = array_search( $field, array_keys( $where_args['data'] ) );
     959            $format = $where_args['format'][ $index ];
     960
     961            $conditions[] = "{$field} = {$format}";
     962            $values[]     = $value;
     963        }
     964
     965        $fields     = implode( ', ', $fields );
     966        $conditions = implode( ' AND ', $conditions );
     967
     968        /** This action is documented in bp-notifications/classes/class-bp-notifications-notification.php */
     969        do_action( 'bp_notification_before_update', $update_args, $where_args );
     970
     971        return $wpdb->query( $wpdb->prepare( "UPDATE {$bp->notifications->table_name} SET {$fields} WHERE {$conditions}", $values ) );
     972    }
     973
     974    /**
    914975     * Delete notifications.
    915976     *
     
    917978     *
    918979     * @see BP_Notifications_Notification::get() for a description of
    919      *      accepted update/where arguments.
     980     *      accepted where arguments.
    920981     *
    921982     * @param array $args Associative array of columns/values, to determine
     
    9391000
    9401001        return self::_delete( $where['data'], $where['format'] );
     1002    }
     1003
     1004    /**
     1005     * Delete notifications using a list of ids/items_ids.
     1006     *
     1007     * @since 10.0.0
     1008     *
     1009     * @param string $field The name of the db field of the items to delete.
     1010     *                      Possible values are `id` or `item_id`.
     1011     * @param int[]  $items The list of items to delete.
     1012     * @param array  $args  The WHERE arguments to use to specify the item IDs to delete.
     1013     * @return int|false    The number of deleted rows. False on error.
     1014     */
     1015    public static function delete_by_id_list( $field, $items = array(), $args = array() ) {
     1016        global $wpdb;
     1017        $bp = buddypress();
     1018
     1019        $supported_fields = array( 'id', 'item_id' );
     1020
     1021        if ( false === in_array( $field, $supported_fields, true ) ) {
     1022            return false;
     1023        }
     1024
     1025        if ( ! is_array( $items ) || ! is_array( $args ) ) {
     1026            return false;
     1027        }
     1028
     1029        $where = self::get_query_clauses( $args );
     1030
     1031        $conditions = array();
     1032        $values     = array();
     1033
     1034        $_items       = implode( ',', wp_parse_id_list( $items ) );
     1035        $conditions[] = "{$field} IN ({$_items})";
     1036
     1037        foreach ( $where['data'] as $field => $value ) {
     1038            $index  = array_search( $field, array_keys( $where['data'] ) );
     1039            $format = $where['format'][ $index ];
     1040
     1041            $conditions[] = "{$field} = {$format}";
     1042            $values[]     = $value;
     1043        }
     1044
     1045        $conditions = implode( ' AND ', $conditions );
     1046
     1047        /** This action is documented in bp-notifications/classes/class-bp-notifications-notification.php */
     1048        do_action( 'bp_notification_before_delete', $args );
     1049
     1050        if ( ! $values ) {
     1051            return $wpdb->query( "DELETE FROM {$bp->notifications->table_name} WHERE {$conditions}" );
     1052        }
     1053
     1054        return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->notifications->table_name} WHERE {$conditions}", $values ) );
    9411055    }
    9421056
Note: See TracChangeset for help on using the changeset viewer.