Почему этот `while` l oop не обрабатывает все записи при изменении данных? - PullRequest
0 голосов
/ 04 мая 2020

У меня есть PHP while l oop в скрипте WordPress, который, кажется, обрабатывает только половину записей, которые он должен делать, когда он изменяет данные, и я изо всех сил пытаюсь понять, почему это происходит.

Я пишу сценарий WP-CLI, который установит мета с ключом reviewed и значением 1 для всех комментариев, у которых его еще нет. Мой скрипт выглядит так:

class Mark_Comments_Reviewed {

    public function __invoke() {

        $limit  = 100;
        $offset = 0;

        while ( $comment_ids = $this->get_unreviewed_comments( $limit, $offset ) ) {

            array_walk(
                $comment_ids,
                function ( $comment_id ) {
                    $comment_id = (int) $comment_id;
                    $this->process_comment( $comment_id );
                }
            );

            $offset += $limit;
        }
    }

    protected function get_unreviewed_comments( int $limit, int $offset ): array {

        global $wpdb;

        return $wpdb->get_col(
            $wpdb->prepare(
                "SELECT DISTINCT comments.comment_ID
                        FROM wp_comments AS comments
                        AND comments.comment_ID NOT IN (
                            SELECT meta.comment_id
                            FROM wp_commentmeta AS meta
                            WHERE meta.meta_key = 'reviewed'
                        )
                        LIMIT %d
                        OFFSET %d",
                $limit,
                $offset
            )
        );
    }

    protected function process_comment( int $comment_id ): bool {
        return ! ! update_comment_meta( $comment_id, 'reviewed', (int) true );
    }

}

(Таблица wp_commentmeta имеет поля meta_id, meta_key, meta_value and comment_id , and the last field relates to the ID of a comment record in the wp_comments` table.)

I есть 810 комментариев без мета. Когда я запускаю скрипт таким образом, он завершает обработку 410. Когда я заменяю строку $this->process_comment( $comment_id ); на return true, скрипт «обрабатывает» все 810.

После восстановления вызова process_comment я необходимо выполнить сценарий четыре раза, чтобы обработать все 810 записей.

  • В первый раз сценарий зацикливается 6 раз и обрабатывает 410 записей. База данных подтверждает 400 остаются. Помимо того, что l oop заканчивается рано, это странно, потому что 6 пакетов по 100 должны быть 600.
  • Во второй раз, это повторяет 3 раза и обрабатывает 200 записей, оставляя 200. Таким образом, это сделано 200 вместо 300.
  • В третий раз он зацикливается 2 раза и обрабатывает 100 записей, оставляя 100.
  • В четвертый раз зацикливается один раз и не оставляет неизменных записей.

Очевидно, что что-то в обновлении мета-комментариев приводит к тому, что l oop заканчивается sh раньше, чем должно. Я что-то упускаю из виду?


РЕДАКТИРОВАТЬ

Я обнаружил, что скрипт обрабатывает только все остальные партии из 100 записей. ?

1 Ответ

0 голосов
/ 04 мая 2020

Aaaargh! Это было смещение! Когда я его удаляю, скрипт обрабатывает все записи, как задумано.

Первая итерация l oop обработала первые 100 записей, удалив их из набора записей, у которых не было мета-значения , Это оставило 710. Но следующая итерация началась со смещения 100, что означало, что первые 100 из этих 710 не были обработаны. Смещение мне не нужно - мне просто нужно было выбирать первый пакет из оставшихся записей каждый раз.

Исправленный сценарий:

class Mark_Comments_Reviewed {

    public function __invoke() {

        $limit  = 100;

        while ( $comment_ids = $this->get_unreviewed_comments( $limit ) ) {
            array_walk(
                $comment_ids,
                function ( $comment_id ) {
                    $comment_id = (int) $comment_id;
                    $this->process_comment( $comment_id );
                }
            );
        }
    }

    protected function get_unreviewed_comments( int $limit ): array {

        global $wpdb;

        return $wpdb->get_col(
            $wpdb->prepare(
                "SELECT DISTINCT comments.comment_ID
                    FROM wp_comments AS comments
                    AND comments.comment_ID NOT IN (
                        SELECT meta.comment_id
                        FROM wp_commentmeta AS meta
                        WHERE meta.meta_key = 'reviewed'
                    )
                    LIMIT %d"
                $limit
            )
        );
    }

    protected function process_comment( int $comment_id ): bool {
        return ! ! update_comment_meta( $comment_id, 'reviewed', (int) true );
    }

}
...