%d AND v.answer_key LIKE %s ORDER BY aa.attempt_id, q.position, q.id', array_merge( array( Db::table( 'attempt_answers' ), Db::table( 'questions' ), Db::table( 'question_versions' ), Db::table( 'question_snapshots' ) ), $attempt_ids, array( AnswerVerdict::RECORDED->value, '%' . $wpdb->esc_like( '"type":"' . QuestionType::ESSAY->slug() . '"' ) . '%' ) ) ); $out = array(); foreach ( $rows as $row ) { if ( QuestionType::ESSAY !== QuestionKey::from_json( (string) $row['answer_key'] )->type ) { continue; } $answer = AttemptRepository::answer( $row ); $live = 1 === (int) $row['q_state'] && (int) $row['current_version_id'] === (int) $row['version_id']; $display = $live || null === $row['s_display'] ? null : QuestionDisplay::from_json( (string) $row['s_display'] ); $out[ (int) $row['attempt_id'] ][] = array( 'question_id' => (int) $row['question_id'], 'uuid' => (string) $row['uuid'], 'unit_id' => (int) $row['unit_id'], 'version_id' => (int) $row['version_id'], 'max' => (float) $row['max_points'], 'points' => $answer['points'], 'pending' => 0 === $answer['verdict']->value, 'text' => is_string( $answer['response']['t'] ?? null ) ? (string) $answer['response']['t'] : '', 'feedback' => (string) ( $answer['feedback'] ?? '' ), 'pinned_text' => null === $display ? null : $display->text, ); } return $out; } public static function question_texts( array $unit_ids, string $lang ): array { $unit_ids = CourseRepository::ids( $unit_ids ); if ( array() === $unit_ids ) { return array(); } $units = Services::unit_repo()->get_many( $unit_ids ); $posts = Services::posts()->for_objects( ObjectType::UNIT, $unit_ids, $lang ); $homes = array(); $parser = Services::question_parser(); foreach ( $units as $unit ) { $homes[] = (int) $unit->home_post_id; } $homes = array_values( array_filter( array_unique( $homes ) ) ); if ( array() !== $homes ) { _prime_post_caches( $homes, false, false ); } $out = array(); foreach ( $unit_ids as $unit_id ) { $home = isset( $units[ $unit_id ] ) ? (int) $units[ $unit_id ]->home_post_id : 0; $post = $posts[ $unit_id ] ?? $home; $texts = array(); foreach ( $home > 0 ? $parser->texts( $home ) : array() as $uuid => $t ) { $texts[ $uuid ] = (string) $t['text']; } if ( $post > 0 && $post !== $home ) { foreach ( $parser->texts( $post ) as $uuid => $t ) { if ( '' !== (string) $t['text'] ) { $texts[ $uuid ] = (string) $t['text']; } } } $out[ $unit_id ] = array_map( 'wp_kses_post', $texts ); } return $out; } public static function names( array $user_ids ): array { $user_ids = CourseRepository::ids( $user_ids ); if ( array() === $user_ids ) { return array(); } $out = array(); foreach ( get_users( array( 'include' => $user_ids, 'fields' => array( 'ID', 'display_name' ), 'count_total' => false, 'orderby' => 'ID', 'blog_id' => 0, ) ) as $user ) { $out[ (int) $user->ID ] = (string) $user->display_name; } return $out; } public static function questions( array $essays, array $texts, string $lang ): array { $frozen = array(); foreach ( $essays as $list ) { foreach ( $list as $essay ) { if ( null !== $essay['pinned_text'] ) { $frozen[] = (int) $essay['version_id']; } } } $translated = array() === $frozen || '' === $lang ? array() : Services::snapshots()->translated( array_values( array_unique( $frozen ) ), $lang ); foreach ( $essays as $attempt_id => $list ) { foreach ( $list as $i => $essay ) { if ( null === $essay['pinned_text'] ) { $html = (string) ( $texts[ $essay['unit_id'] ][ $essay['uuid'] ] ?? '' ); } else { $text = (string) ( $translated[ $essay['version_id'] ]['text'] ?? '' ); $html = wp_kses_post( '' !== $text ? $text : (string) $essay['pinned_text'] ); } $essays[ $attempt_id ][ $i ]['question'] = $html; } } return $essays; } public static function page( array $rows, string $lang ): array { $users = array(); $courses = array(); $units = array(); $ids = array(); foreach ( $rows as $row ) { $users[] = $row->user_id; $courses[] = $row->course_id; $units[] = $row->unit_id; $ids[] = $row->attempt_id; } $texts = self::question_texts( $units, $lang ); return array( 'names' => self::names( $users ), 'courses' => Services::posts()->titles( ObjectType::COURSE, $courses, $lang ), 'quizzes' => Services::posts()->titles( ObjectType::UNIT, $units, $lang ), 'essays' => self::questions( self::essays( $ids ), $texts, $lang ), 'texts' => $texts, ); } }