From 1ae868e3a2eee6022a3e868c1d6533d8b0f212be Mon Sep 17 00:00:00 2001 From: Dmitry Merkushin Date: Wed, 27 Sep 2023 09:23:32 -0600 Subject: [PATCH] Update find methods to work with multiple values in filters --- includes/class-sensei-modules.php | 8 +-- includes/class-sensei-quiz.php | 22 +++++++- includes/class-sensei-utils.php | 38 +++++++------- .../class-sensei-course-theme-lesson.php | 9 ++-- ...ments-based-course-progress-repository.php | 50 +++++++++++++++++-- ...ables-based-course-progress-repository.php | 32 +++++++++--- ...ments-based-lesson-progress-repository.php | 44 ++++++++++++++-- ...ables-based-lesson-progress-repository.php | 36 +++++++++---- ...omments-based-quiz-progress-repository.php | 50 ++++++++++++++++--- ...ing-aggregate-quiz-progress-repository.php | 2 +- ...-tables-based-quiz-progress-repository.php | 34 +++++++++---- ...g-aggregate-course-progress-repository.php | 10 +++- ...ments-based-course-progress-repository.php | 4 +- ...g-aggregate-course-progress-repository.php | 10 +++- ...ables-based-course-progress-repository.php | 8 ++- ...g-aggregate-lesson-progress-repository.php | 10 +++- ...ments-based-lesson-progress-repository.php | 4 +- ...g-aggregate-lesson-progress-repository.php | 10 +++- ...ables-based-lesson-progress-repository.php | 2 +- ...ing-aggregate-quiz-progress-repository.php | 11 ++-- ...ing-aggregate-quiz-progress-repository.php | 10 +++- ...-tables-based-quiz-progress-repository.php | 2 +- tests/unit-tests/test-class-quiz.php | 24 +++++++++ 23 files changed, 334 insertions(+), 96 deletions(-) diff --git a/includes/class-sensei-modules.php b/includes/class-sensei-modules.php index bfc447d5866..c44b6125300 100644 --- a/includes/class-sensei-modules.php +++ b/includes/class-sensei-modules.php @@ -743,13 +743,7 @@ public function sensei_course_preview_titles( $title, $lesson_id ) { $title_text = ''; if ( method_exists( 'Sensei_Utils', 'is_preview_lesson' ) && Sensei_Utils::is_preview_lesson( $lesson_id ) ) { - $is_user_taking_course = Sensei_Utils::sensei_check_for_activity( - array( - 'post_id' => $course_id, - 'user_id' => $current_user->ID, - 'type' => 'sensei_course_status', - ) - ); + $is_user_taking_course = Sensei()->course_progress_repository->has( $course_id, $current_user->ID ); if ( ! $is_user_taking_course ) { if ( method_exists( 'Sensei_Frontend', 'sensei_lesson_preview_title_text' ) ) { $title_text = Sensei()->frontend->sensei_lesson_preview_title_text( $course_id ); diff --git a/includes/class-sensei-quiz.php b/includes/class-sensei-quiz.php index 4c4d90ce2ba..56b286afbe4 100755 --- a/includes/class-sensei-quiz.php +++ b/includes/class-sensei-quiz.php @@ -230,7 +230,6 @@ public function update_after_lesson_change( $post_id ) { wp_update_post( $my_post ); } - /** * Get the lesson this quiz belongs to. * @@ -255,6 +254,27 @@ public function get_lesson_id( $quiz_id = null ) { } + /** + * Get lesson ids for given quizzes. + * + * @since $$next-version$$ + * + * @param int[] $quiz_ids The quiz IDs. + * @return array Lesson ids, empty array if no lessons found. + */ + public function get_lesson_ids( array $quiz_ids ) { + $quiz_parents = get_posts( + array( + 'fields' => 'post_parent', + 'post_type' => 'quiz', + 'post__in' => $quiz_ids, + 'posts_per_page' => -1, + ) + ); + + return wp_list_pluck( $quiz_parents, 'post_parent' ); + } + /** * This function hooks into the quiz page and accepts the answer form save post. * diff --git a/includes/class-sensei-utils.php b/includes/class-sensei-utils.php index 30f02b52b01..0d0197c0981 100644 --- a/includes/class-sensei-utils.php +++ b/includes/class-sensei-utils.php @@ -102,7 +102,6 @@ public static function sensei_log_activity( $args = array() ) { } } - /** * Check for Sensei activity. * @@ -2818,29 +2817,28 @@ public static function get_target_page_post_id_for_continue_url( $course_id, $us return $course_id; } // First try to get the lesson the user started or updated last. - $activity_args = [ - 'post__in' => $course_lessons, - 'user_id' => $user_id, - 'type' => 'sensei_lesson_status', - 'number' => 1, - 'orderby' => 'comment_date', - 'order' => 'DESC', - 'status' => [ 'in-progress', 'ungraded' ], - ]; + $progress_args = array( + 'lesson_id' => $course_lessons, + 'user_id' => $user_id, + 'status' => array( 'in-progress' ), + 'orderby' => 'updated_at', + 'order' => 'DESC', + 'number' => 1, + ); + $last_progress = Sensei()->lesson_progress_repository->find( $progress_args ); - $last_lesson_activity = self::sensei_check_for_activity( $activity_args, true ); + if ( count( $last_progress ) > 0 ) { + return $last_progress[0]->get_lesson_id(); + } - if ( ! empty( $last_lesson_activity ) ) { - return $last_lesson_activity->comment_post_ID; - } else { - // If there is no such lesson, get the first lesson that the user has not yet started. - $completed_lessons = Sensei()->course->get_completed_lesson_ids( $course_id, $user_id ); - $not_completed_lessons = array_diff( $course_lessons, $completed_lessons ); + // If there is no such lesson, get the first lesson that the user has not yet started. + $completed_lessons = Sensei()->course->get_completed_lesson_ids( $course_id, $user_id ); + $not_completed_lessons = array_diff( $course_lessons, $completed_lessons ); - if ( $not_completed_lessons ) { - return current( $not_completed_lessons ); - } + if ( $not_completed_lessons ) { + return current( $not_completed_lessons ); } + return $course_id; } diff --git a/includes/course-theme/class-sensei-course-theme-lesson.php b/includes/course-theme/class-sensei-course-theme-lesson.php index ac950c5121f..9e7c7f5dcc1 100644 --- a/includes/course-theme/class-sensei-course-theme-lesson.php +++ b/includes/course-theme/class-sensei-course-theme-lesson.php @@ -7,6 +7,7 @@ */ use Sensei\Internal\Student_Progress\Quiz_Progress\Models\Quiz_Progress; +use Sensei\Internal\Student_Progress\Quiz_Progress\Models\Quiz_Progress_Interface; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. @@ -143,10 +144,10 @@ private function maybe_add_quiz_results_notice() { /** * Maybe add lesson quiz progress notice. * - * @param array|false $user_answers User answers. - * @param Quiz_Progress|null $quiz_progress Quiz progress. - * @param int $quiz_id Quiz ID. - * @param Sensei_Context_Notices $notices Notices instance. + * @param array|false $user_answers User answers. + * @param Quiz_Progress_Interface|null $quiz_progress Quiz progress. + * @param int $quiz_id Quiz ID. + * @param Sensei_Context_Notices $notices Notices instance. * * @return bool Whether notice was added. */ diff --git a/includes/internal/student-progress/course-progress/repositories/class-comments-based-course-progress-repository.php b/includes/internal/student-progress/course-progress/repositories/class-comments-based-course-progress-repository.php index 0aff1fe1bb8..be7018e435d 100644 --- a/includes/internal/student-progress/course-progress/repositories/class-comments-based-course-progress-repository.php +++ b/includes/internal/student-progress/course-progress/repositories/class-comments-based-course-progress-repository.php @@ -84,6 +84,10 @@ public function get( int $course_id, int $user_id ): ?Course_Progress_Interface $comment = reset( $comment ); } + if ( ! $comment instanceof WP_Comment ) { + return null; + } + return $this->create_progress_from_comment( $comment ); } @@ -94,7 +98,7 @@ public function get( int $course_id, int $user_id ): ?Course_Progress_Interface * @return Comments_Based_Course_Progress The course progress. */ private function create_progress_from_comment( WP_Comment $comment ): Comments_Based_Course_Progress { - $meta_start = get_comment_meta( $comment->comment_ID, 'start', true ); + $meta_start = get_comment_meta( (int) $comment->comment_ID, 'start', true ); $started_at = $meta_start ? new DateTime( $meta_start, wp_timezone() ) : current_datetime(); $comment_date = new DateTime( $comment->comment_date, wp_timezone() ); @@ -274,7 +278,11 @@ public function find( array $args ): array { ); if ( isset( $args['course_id'] ) ) { - $comments_args['post_id'] = $args['course_id']; + if ( is_array( $args['course_id'] ) ) { + $comments_args['post__in'] = $args['course_id']; + } else { + $comments_args['post_id'] = $args['course_id']; + } } if ( isset( $args['user_id'] ) ) { @@ -285,6 +293,38 @@ public function find( array $args ): array { $comments_args['status'] = $args['status']; } + if ( isset( $args['order'] ) ) { + $comments_args['order'] = $args['order']; + } + + if ( isset( $args['orderby'] ) ) { + switch ( $args['orderby'] ) { + case 'started_at': + throw new \InvalidArgumentException( 'Ordering by started_at is not supported in comments-based version.' ); + case 'completed_at': + case 'created_at': + case 'updated_at': + $comments_args['orderby'] = 'comment_date'; + break; + case 'course_id': + $comments_args['orderby'] = 'comment_post_ID'; + break; + case 'id': + $comments_args['orderby'] = 'comment_ID'; + break; + case 'status': + $comments_args['orderby'] = 'comment_approved'; + break; + default: + $comments_args['orderby'] = $args['orderby']; + break; + } + } + + if ( isset( $args['order'] ) ) { + $comments_args['order'] = $args['order']; + } + if ( isset( $args['offset'] ) ) { $comments_args['offset'] = $args['offset']; } @@ -294,10 +334,12 @@ public function find( array $args ): array { } $comments = \Sensei_Utils::sensei_check_for_activity( $comments_args, true ); - if ( ! $comments ) { - return []; + if ( empty( $comments ) ) { + return array(); } + $comments = is_array( $comments ) ? $comments : array( $comments ); + $course_progresses = []; foreach ( $comments as $comment ) { $course_progresses[] = $this->create_progress_from_comment( $comment ); diff --git a/includes/internal/student-progress/course-progress/repositories/class-tables-based-course-progress-repository.php b/includes/internal/student-progress/course-progress/repositories/class-tables-based-course-progress-repository.php index 0e59145b1da..5813b905c6a 100644 --- a/includes/internal/student-progress/course-progress/repositories/class-tables-based-course-progress-repository.php +++ b/includes/internal/student-progress/course-progress/repositories/class-tables-based-course-progress-repository.php @@ -292,8 +292,8 @@ public function find( array $args ): array { $where_clause = array( 'type = %s' ); $query_params = array( 'course' ); if ( ! is_null( $course_id ) ) { - $query_params[] = (int) $course_id; - $where_clause[] = 'post_id = %d'; + $query_params = array_merge( $query_params, (array) $course_id ); + $where_clause[] = 'post_id IN (' . $this->get_placeholders( (array) $course_id ) . ')'; } if ( ! is_null( $user_id ) ) { @@ -302,8 +302,8 @@ public function find( array $args ): array { } if ( ! is_null( $status ) ) { - $query_params[] = $status; - $where_clause[] = 'status = %s'; + $query_params = array_merge( $query_params, (array) $status ); + $where_clause[] = 'status IN (' . $this->get_placeholders( (array) $status ) . ')'; } $table_name = $this->wpdb->prefix . 'sensei_lms_progress'; @@ -314,14 +314,13 @@ public function find( array $args ): array { $query_string .= 'WHERE ' . implode( ' AND ', $where_clause ) . ' '; } - $query_string .= 'ORDER BY id ASC '; - $query_string .= 'LIMIT %d OFFSET %d'; + $query_string .= 'ORDER BY id ASC '; + $query_string .= 'LIMIT %d OFFSET %d'; $query_params[] = $limit; $query_params[] = $offset; - $query = $this->wpdb->prepare( - $query_string, + $query_string, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared ...$query_params ); @@ -349,4 +348,21 @@ public function find( array $args ): array { return $course_progresses; } + + /** + * Return a string of placeholders for the given values. + * + * @param array $values The values. + * @return string The placeholders. + */ + private function get_placeholders( array $values ) { + if ( empty( $values ) ) { + return ''; + } + + $placeholder = is_numeric( $values[0] ) ? '%d' : '%s'; + $placeholders = array_fill( 0, count( $values ), $placeholder ); + + return implode( ', ', $placeholders ); + } } diff --git a/includes/internal/student-progress/lesson-progress/repositories/class-comments-based-lesson-progress-repository.php b/includes/internal/student-progress/lesson-progress/repositories/class-comments-based-lesson-progress-repository.php index 3bef5bf74d2..04d0a6f270a 100644 --- a/includes/internal/student-progress/lesson-progress/repositories/class-comments-based-lesson-progress-repository.php +++ b/includes/internal/student-progress/lesson-progress/repositories/class-comments-based-lesson-progress-repository.php @@ -73,7 +73,7 @@ public function get( int $lesson_id, int $user_id ): ?Lesson_Progress_Interface 'type' => 'sensei_lesson_status', ]; $comment = Sensei_Utils::sensei_check_for_activity( $activity_args, true ); - if ( ! $comment ) { + if ( ! $comment instanceof WP_Comment ) { return null; } @@ -273,7 +273,7 @@ public function find( array $args ): array { ); if ( isset( $args['lesson_id'] ) ) { - $comments_args['post_id'] = $args['lesson_id']; + $comments_args['post__in'] = (array) $args['lesson_id']; } if ( isset( $args['user_id'] ) ) { @@ -284,6 +284,38 @@ public function find( array $args ): array { $comments_args['status'] = $args['status']; } + if ( isset( $args['order'] ) ) { + $comments_args['order'] = $args['order']; + } + + if ( isset( $args['orderby'] ) ) { + switch ( $args['orderby'] ) { + case 'started_at': + throw new \InvalidArgumentException( 'Ordering by started_at is not supported in comments-based version.' ); + case 'completed_at': + case 'created_at': + case 'updated_at': + $comments_args['orderby'] = 'comment_date'; + break; + case 'lesson_id': + $comments_args['orderby'] = 'comment_post_ID'; + break; + case 'id': + $comments_args['orderby'] = 'comment_ID'; + break; + case 'status': + $comments_args['orderby'] = 'comment_approved'; + break; + default: + $comments_args['orderby'] = $args['orderby']; + break; + } + } + + if ( isset( $args['order'] ) ) { + $comments_args['order'] = $args['order']; + } + if ( isset( $args['offset'] ) ) { $comments_args['offset'] = $args['offset']; } @@ -293,10 +325,12 @@ public function find( array $args ): array { } $comments = \Sensei_Utils::sensei_check_for_activity( $comments_args, true ); - if ( ! $comments ) { - return []; + if ( empty( $comments ) ) { + return array(); } + $comments = is_array( $comments ) ? $comments : array( $comments ); + $lesson_progresses = []; foreach ( $comments as $comment ) { $lesson_progresses[] = $this->create_progress_from_comment( $comment ); @@ -313,7 +347,7 @@ public function find( array $args ): array { */ private function create_progress_from_comment( WP_Comment $comment ): Comments_Based_Lesson_Progress { $comment_date = new DateTime( $comment->comment_date, wp_timezone() ); - $meta_start = get_comment_meta( $comment->comment_ID, 'start', true ); + $meta_start = get_comment_meta( (int) $comment->comment_ID, 'start', true ); $started_at = ! empty( $meta_start ) ? new DateTime( $meta_start, wp_timezone() ) : current_datetime(); if ( in_array( $comment->comment_approved, [ 'complete', 'passed', 'graded' ], true ) ) { diff --git a/includes/internal/student-progress/lesson-progress/repositories/class-tables-based-lesson-progress-repository.php b/includes/internal/student-progress/lesson-progress/repositories/class-tables-based-lesson-progress-repository.php index 2a214ee5cc3..70105cc4fb3 100644 --- a/includes/internal/student-progress/lesson-progress/repositories/class-tables-based-lesson-progress-repository.php +++ b/includes/internal/student-progress/lesson-progress/repositories/class-tables-based-lesson-progress-repository.php @@ -319,7 +319,7 @@ private function assert_tables_based_lesson_progress( Lesson_Progress_Interface * @return Lesson_Progress_Interface[] */ public function find( array $args ): array { - $course_id = $args['course_id'] ?? null; + $lesson_id = $args['lesson_id'] ?? null; $user_id = $args['user_id'] ?? null; $status = $args['status'] ?? null; $limit = $args['number'] ?? 100; @@ -327,9 +327,9 @@ public function find( array $args ): array { $where_clause = array( 'type = %s' ); $query_params = array( 'lesson' ); - if ( ! is_null( $course_id ) ) { - $query_params[] = (int) $course_id; - $where_clause[] = 'post_id = %d'; + if ( ! is_null( $lesson_id ) ) { + $query_params = array_merge( $query_params, (array) $lesson_id ); + $where_clause[] = 'post_id IN (' . $this->get_placeholders( (array) $lesson_id ) . ')'; } if ( ! is_null( $user_id ) ) { @@ -338,8 +338,8 @@ public function find( array $args ): array { } if ( ! is_null( $status ) ) { - $query_params[] = $status; - $where_clause[] = 'status = %s'; + $query_params = array_merge( $query_params, (array) $status ); + $where_clause[] = 'status IN (' . $this->get_placeholders( (array) $status ) . ')'; } $table_name = $this->wpdb->prefix . 'sensei_lms_progress'; @@ -350,14 +350,13 @@ public function find( array $args ): array { $query_string .= 'WHERE ' . implode( ' AND ', $where_clause ) . ' '; } - $query_string .= 'ORDER BY id ASC '; - $query_string .= 'LIMIT %d OFFSET %d'; + $query_string .= 'ORDER BY id ASC '; + $query_string .= 'LIMIT %d OFFSET %d'; $query_params[] = $limit; $query_params[] = $offset; - $query = $this->wpdb->prepare( - $query_string, + $query_string, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared ...$query_params ); @@ -385,4 +384,21 @@ public function find( array $args ): array { return $lesson_progresses; } + + /** + * Return a string of placeholders for the given values. + * + * @param array $values The values. + * @return string The placeholders. + */ + private function get_placeholders( array $values ) { + if ( empty( $values ) ) { + return ''; + } + + $placeholder = is_numeric( $values[0] ) ? '%d' : '%s'; + $placeholders = array_fill( 0, count( $values ), $placeholder ); + + return implode( ', ', $placeholders ); + } } diff --git a/includes/internal/student-progress/quiz-progress/repositories/class-comments-based-quiz-progress-repository.php b/includes/internal/student-progress/quiz-progress/repositories/class-comments-based-quiz-progress-repository.php index a0aceed82af..2a5c872fffd 100644 --- a/includes/internal/student-progress/quiz-progress/repositories/class-comments-based-quiz-progress-repository.php +++ b/includes/internal/student-progress/quiz-progress/repositories/class-comments-based-quiz-progress-repository.php @@ -70,7 +70,7 @@ public function get( int $quiz_id, int $user_id ): ?Quiz_Progress_Interface { 'type' => 'sensei_lesson_status', ]; $comment = Sensei_Utils::sensei_check_for_activity( $activity_args, true ); - if ( ! $comment ) { + if ( ! $comment instanceof WP_Comment ) { return null; } @@ -203,7 +203,7 @@ private function assert_comments_based_quiz_progress( Quiz_Progress_Interface $q * @internal * * @param array $args The arguments. - * @return Course_Progress_Interface[] The course progress. + * @return Quiz_Progress_Interface[] The course progress. */ public function find( array $args ): array { $comments_args = array( @@ -214,9 +214,9 @@ public function find( array $args ): array { $quiz_id = $args['quiz_id'] ?? null; if ( isset( $args['quiz_id'] ) ) { - $lesson_id = Sensei()->quiz->get_lesson_id( $args['quiz_id'] ); - if ( $lesson_id ) { - $comments_args['post_id'] = $args['course_id']; + $lesson_ids = Sensei()->quiz->get_lesson_ids( (array) $args['quiz_id'] ); + if ( ! empty( $lesson_ids ) ) { + $comments_args['post__in'] = $lesson_ids; } else { return array(); } @@ -230,6 +230,39 @@ public function find( array $args ): array { $comments_args['status'] = $args['status']; } + if ( isset( $args['order'] ) ) { + $comments_args['order'] = $args['order']; + } + + if ( isset( $args['orderby'] ) ) { + switch ( $args['orderby'] ) { + case 'started_at': + throw new \InvalidArgumentException( 'Ordering by started_at is not supported in comments-based version.' ); + case 'completed_at': + case 'created_at': + case 'updated_at': + $comments_args['orderby'] = 'comment_date'; + break; + case 'quiz_id': + // We need to order by lesson ID, not quiz ID, as the lesson ID is not reachable from the comment. + $comments_args['orderby'] = 'comment_post_ID'; + break; + case 'id': + $comments_args['orderby'] = 'comment_ID'; + break; + case 'status': + $comments_args['orderby'] = 'comment_approved'; + break; + default: + $comments_args['orderby'] = $args['orderby']; + break; + } + } + + if ( isset( $args['order'] ) ) { + $comments_args['order'] = $args['order']; + } + if ( isset( $args['offset'] ) ) { $comments_args['offset'] = $args['offset']; } @@ -239,10 +272,12 @@ public function find( array $args ): array { } $comments = \Sensei_Utils::sensei_check_for_activity( $comments_args, true ); - if ( ! $comments ) { + if ( empty( $comments ) ) { return array(); } + $comments = is_array( $comments ) ? $comments : array( $comments ); + $quiz_progresses = []; foreach ( $comments as $comment ) { $quiz_progresses[] = $this->create_progress_from_comment( $comment, $quiz_id ); @@ -255,11 +290,12 @@ public function find( array $args ): array { * Create a lesson progress from a comment. * * @param WP_Comment $comment The comment. + * @param int|null $quiz_id The quiz ID that is associated with the status comment. * @return Comments_Based_Quiz_Progress The course progress. */ private function create_progress_from_comment( WP_Comment $comment, ?int $quiz_id = null ): Comments_Based_Quiz_Progress { $comment_date = new DateTime( $comment->comment_date, wp_timezone() ); - $meta_start = get_comment_meta( $comment->comment_ID, 'start', true ); + $meta_start = get_comment_meta( (int) $comment->comment_ID, 'start', true ); $started_at = ! empty( $meta_start ) ? new DateTime( $meta_start, wp_timezone() ) : current_datetime(); if ( in_array( $comment->comment_approved, [ 'complete', 'passed', 'graded' ], true ) ) { diff --git a/includes/internal/student-progress/quiz-progress/repositories/class-table-reading-aggregate-quiz-progress-repository.php b/includes/internal/student-progress/quiz-progress/repositories/class-table-reading-aggregate-quiz-progress-repository.php index 09ce278bced..2bb6c0c1057 100644 --- a/includes/internal/student-progress/quiz-progress/repositories/class-table-reading-aggregate-quiz-progress-repository.php +++ b/includes/internal/student-progress/quiz-progress/repositories/class-table-reading-aggregate-quiz-progress-repository.php @@ -151,7 +151,7 @@ public function delete_for_user( int $user_id ): void { * @internal * * @param array $args The arguments. - * @return Tables_Based_Quiz_Progress[] The course progress. + * @return Quiz_Progress_Interface[] The course progress. */ public function find( array $args ): array { return $this->tables_based_repository->find( $args ); diff --git a/includes/internal/student-progress/quiz-progress/repositories/class-tables-based-quiz-progress-repository.php b/includes/internal/student-progress/quiz-progress/repositories/class-tables-based-quiz-progress-repository.php index 43937d0c73f..e033820dda8 100644 --- a/includes/internal/student-progress/quiz-progress/repositories/class-tables-based-quiz-progress-repository.php +++ b/includes/internal/student-progress/quiz-progress/repositories/class-tables-based-quiz-progress-repository.php @@ -291,8 +291,8 @@ public function find( array $args ): array { $where_clause = array( 'type = %s' ); $query_params = array( 'quiz' ); if ( ! is_null( $quiz_id ) ) { - $query_params[] = (int) $quiz_id; - $where_clause[] = 'post_id = %d'; + $query_params = array_merge( $query_params, (array) $quiz_id ); + $where_clause[] = 'post_id IN (' . $this->get_placeholders( (array) $quiz_id ) . ')'; } if ( ! is_null( $user_id ) ) { @@ -301,8 +301,8 @@ public function find( array $args ): array { } if ( ! is_null( $status ) ) { - $query_params[] = $status; - $where_clause[] = 'status = %s'; + $query_params = array_merge( $query_params, (array) $status ); + $where_clause[] = 'status IN (' . $this->get_placeholders( (array) $status ) . ')'; } $table_name = $this->wpdb->prefix . 'sensei_lms_progress'; @@ -310,17 +310,16 @@ public function find( array $args ): array { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $query_string = 'SELECT * FROM ' . $table_name . ' '; if ( count( $where_clause ) > 0 ) { - $query_string .= 'WHERE ' .implode( ' AND ', $where_clause ) . ' '; + $query_string .= 'WHERE ' . implode( ' AND ', $where_clause ) . ' '; } - $query_string .= 'ORDER BY id ASC '; - $query_string .= 'LIMIT %d OFFSET %d'; + $query_string .= 'ORDER BY id ASC '; + $query_string .= 'LIMIT %d OFFSET %d'; $query_params[] = $limit; $query_params[] = $offset; - $query = $this->wpdb->prepare( - $query_string, + $query_string, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared ...$query_params ); @@ -348,4 +347,21 @@ public function find( array $args ): array { return $course_progresses; } + + /** + * Return a string of placeholders for the given values. + * + * @param array $values The values. + * @return string The placeholders. + */ + private function get_placeholders( array $values ) { + if ( empty( $values ) ) { + return ''; + } + + $placeholder = is_numeric( $values[0] ) ? '%d' : '%s'; + $placeholders = array_fill( 0, count( $values ), $placeholder ); + + return implode( ', ', $placeholders ); + } } diff --git a/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-comment-reading-aggregate-course-progress-repository.php b/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-comment-reading-aggregate-course-progress-repository.php index 9c5dbe8ea95..13dfa0d2942 100644 --- a/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-comment-reading-aggregate-course-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-comment-reading-aggregate-course-progress-repository.php @@ -273,7 +273,10 @@ public function testFind_Always_CallsCommentsBasedRepository(): void { $repository = new Comment_Reading_Aggregate_Course_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $comments_based @@ -290,7 +293,10 @@ public function testFind_Never_CallsTablesBasedRepository(): void { $repository = new Comment_Reading_Aggregate_Course_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $tables_based diff --git a/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-comments-based-course-progress-repository.php b/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-comments-based-course-progress-repository.php index 5a559556a44..bce0f501a79 100644 --- a/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-comments-based-course-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-comments-based-course-progress-repository.php @@ -213,7 +213,7 @@ public function testFind_ArgumentsGiven_ReturnsMatchingProgress(): void { $course_ids = $this->factory->course->create_many( 5 ); $user_id = $this->factory->user->create(); - $repository = new Comments_Based_Course_Progress_Repository(); + $repository = new Comments_Based_Course_Progress_Repository(); $created_progress = []; foreach ( $course_ids as $course_id ) { $created_progress[] = $repository->create( $course_id, $user_id ); @@ -221,7 +221,7 @@ public function testFind_ArgumentsGiven_ReturnsMatchingProgress(): void { $expected = array(); for ( $i = 0; $i < 3; $i++ ) { - $progress = $created_progress[ $i ]; + $progress = $created_progress[ $i ]; $progress->complete(); $repository->save( $progress ); $expected[] = $this->export_progress( $progress ); diff --git a/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-table-reading-aggregate-course-progress-repository.php b/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-table-reading-aggregate-course-progress-repository.php index 01185a9a5b2..888ad7fece8 100644 --- a/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-table-reading-aggregate-course-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-table-reading-aggregate-course-progress-repository.php @@ -347,7 +347,10 @@ public function testFind_Always_CallsTablesBasedRepository(): void { $repository = new Table_Reading_Aggregate_Course_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $tables_based @@ -364,7 +367,10 @@ public function testFind_Never_CallsCommentsBasedRepository(): void { $repository = new Table_Reading_Aggregate_Course_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $comments_based diff --git a/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-tables-based-course-progress-repository.php b/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-tables-based-course-progress-repository.php index d311c2c9de1..a0d61093891 100644 --- a/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-tables-based-course-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/course-progress/repositories/test-class-tables-based-course-progress-repository.php @@ -402,7 +402,7 @@ public function testIntegrationFind_ArgumentsGiven_ReturnsMatchingProgress(): vo $course_ids = $this->factory->course->create_many( 5 ); $user_id = $this->factory->user->create(); - $repository = new Tables_Based_Course_Progress_Repository( $wpdb ); + $repository = new Tables_Based_Course_Progress_Repository( $wpdb ); $created_progress = []; foreach ( $course_ids as $course_id ) { $created_progress[] = $repository->create( $course_id, $user_id ); @@ -424,6 +424,12 @@ public function testIntegrationFind_ArgumentsGiven_ReturnsMatchingProgress(): vo ) ); $actual = array_map( array( $this, 'export_progress' ), $found_progress ); + usort( + $actual, + function( $a, $b ) { + return $a['course_id'] <=> $b['course_id']; + } + ); /* Assert. */ self::assertSame( $expected, $actual ); diff --git a/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-comment-reading-aggregate-lesson-progress-repository.php b/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-comment-reading-aggregate-lesson-progress-repository.php index 67b3bf4cd1c..3cf843172f0 100644 --- a/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-comment-reading-aggregate-lesson-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-comment-reading-aggregate-lesson-progress-repository.php @@ -300,7 +300,10 @@ public function testFind_Always_CallsCommentsBasedRepository(): void { $repository = new Comment_Reading_Aggregate_Lesson_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $comments_based @@ -317,7 +320,10 @@ public function testFind_Never_CallsTablesBasedRepository(): void { $repository = new Comment_Reading_Aggregate_Lesson_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $tables_based diff --git a/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-comments-based-lesson-progress-repository.php b/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-comments-based-lesson-progress-repository.php index c1fafdedd77..88834c15574 100644 --- a/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-comments-based-lesson-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-comments-based-lesson-progress-repository.php @@ -204,7 +204,7 @@ public function testFind_ArgumentsGiven_ReturnsMatchingProgress(): void { $lesson_ids = $this->factory->lesson->create_many( 5 ); $user_id = $this->factory->user->create(); - $repository = new Comments_Based_Lesson_Progress_Repository(); + $repository = new Comments_Based_Lesson_Progress_Repository(); $created_progress = []; foreach ( $lesson_ids as $lesson_id ) { $created_progress[] = $repository->create( $lesson_id, $user_id ); @@ -212,7 +212,7 @@ public function testFind_ArgumentsGiven_ReturnsMatchingProgress(): void { $expected = array(); for ( $i = 0; $i < 3; $i++ ) { - $progress = $created_progress[ $i ]; + $progress = $created_progress[ $i ]; $progress->complete(); $repository->save( $progress ); $expected[] = $this->export_progress( $progress ); diff --git a/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-table-reading-aggregate-lesson-progress-repository.php b/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-table-reading-aggregate-lesson-progress-repository.php index 660277c1fd6..169e07d54e9 100644 --- a/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-table-reading-aggregate-lesson-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-table-reading-aggregate-lesson-progress-repository.php @@ -364,7 +364,10 @@ public function testFind_Always_CallsTablesBasedRepository(): void { $repository = new Table_Reading_Aggregate_Lesson_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $tables_based @@ -381,7 +384,10 @@ public function testFind_Never_CallsCommentsBasedRepository(): void { $repository = new Table_Reading_Aggregate_Lesson_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $comments_based diff --git a/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-tables-based-lesson-progress-repository.php b/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-tables-based-lesson-progress-repository.php index aac9842c4a6..bf6f6fce2d5 100644 --- a/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-tables-based-lesson-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/lesson-progress/repositories/test-class-tables-based-lesson-progress-repository.php @@ -435,7 +435,7 @@ public function testIntegrationFind_ArgumentsGiven_ReturnsMatchingProgress(): vo $lesson_ids = $this->factory->lesson->create_many( 5 ); $user_id = $this->factory->user->create(); - $repository = new Tables_Based_Lesson_Progress_Repository( $wpdb ); + $repository = new Tables_Based_Lesson_Progress_Repository( $wpdb ); $created_progress = []; foreach ( $lesson_ids as $lesson_id ) { $created_progress[] = $repository->create( $lesson_id, $user_id ); diff --git a/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-comment-reading-aggregate-quiz-progress-repository.php b/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-comment-reading-aggregate-quiz-progress-repository.php index 81f9739ebf8..6f3b3669f94 100644 --- a/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-comment-reading-aggregate-quiz-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-comment-reading-aggregate-quiz-progress-repository.php @@ -277,7 +277,10 @@ public function testFind_Always_CallsCommentsBasedRepository(): void { $repository = new Comment_Reading_Aggregate_Quiz_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $comments_based @@ -292,10 +295,12 @@ public function testFind_Never_CallsTablesBasedRepository(): void { $comments_based = $this->createMock( Comments_Based_Quiz_Progress_Repository::class ); $tables_based = $this->createMock( Tables_Based_Quiz_Progress_Repository::class ); - $repository = new Comment_Reading_Aggregate_Quiz_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $tables_based diff --git a/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-table-reading-aggregate-quiz-progress-repository.php b/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-table-reading-aggregate-quiz-progress-repository.php index a28259332a0..7e7e4d7e6b4 100644 --- a/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-table-reading-aggregate-quiz-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-table-reading-aggregate-quiz-progress-repository.php @@ -347,7 +347,10 @@ public function testFind_Always_CallsTablesBasedRepository(): void { $repository = new Table_Reading_Aggregate_Quiz_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $tables_based @@ -364,7 +367,10 @@ public function testFind_Never_CallsCommentsBasedRepository(): void { $repository = new Table_Reading_Aggregate_Quiz_Progress_Repository( $comments_based, $tables_based ); - $args = array( 'a' => 1, 'b' => 2 ); + $args = array( + 'a' => 1, + 'b' => 2, + ); /* Expect & Act. */ $comments_based diff --git a/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-tables-based-quiz-progress-repository.php b/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-tables-based-quiz-progress-repository.php index e7b62fc4d3e..b845909f25c 100644 --- a/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-tables-based-quiz-progress-repository.php +++ b/tests/unit-tests/internal/student-progress/quiz-progress/repositories/test-class-tables-based-quiz-progress-repository.php @@ -401,7 +401,7 @@ public function testIntegrationFind_ArgumentsGiven_ReturnsMatchingProgress(): vo $quiz_ids = $this->factory->quiz->create_many( 5 ); $user_id = $this->factory->user->create(); - $repository = new Tables_Based_Quiz_Progress_Repository( $wpdb ); + $repository = new Tables_Based_Quiz_Progress_Repository( $wpdb ); $created_progress = []; foreach ( $quiz_ids as $quiz_id ) { $created_progress[] = $repository->create( $quiz_id, $user_id ); diff --git a/tests/unit-tests/test-class-quiz.php b/tests/unit-tests/test-class-quiz.php index c6927e3b239..2318bb7f5e1 100644 --- a/tests/unit-tests/test-class-quiz.php +++ b/tests/unit-tests/test-class-quiz.php @@ -1950,4 +1950,28 @@ public function testMaybeCreateQuizProgress_WhenTablesBasedProgressFeatureIsDisa $actual = $quiz_progress_repository->has( $quiz_id, $user_id ); $this->assertFalse( $actual ); } + + public function testGetLessonIds_QuizIdsGiven_ReturnsMatchingIds(): void { + /* Arrange. */ + $lesson_ids = $this->factory->lesson->create_many( 3 ); + $quiz_ids = array(); + foreach ( $lesson_ids as $lesson_id ) { + $quiz_ids[] = $this->factory->quiz->create( + array( + 'post_parent' => $lesson_id, + 'meta_input' => array( + '_quiz_lesson' => $lesson_id, + ), + ) + ); + } + + /* Act. */ + $actual = Sensei()->quiz->get_lesson_ids( $quiz_ids ); + + /* Assert. */ + sort( $lesson_ids ); + sort( $actual ); + $this->assertSame( $lesson_ids, $actual ); + } }