includes/class.llms.query.quiz.attempt.php
<?php
/**
* Query LifterLMS Students for a given course / membership
*
* @package LifterLMS/Classes
*
* @since 3.16.0
* @version 6.0.0
*/
defined( 'ABSPATH' ) || exit;
/**
* Query LifterLMS Students for a given course / membership
*
* @since 3.16.0
* @since 3.35.0 Unknown.
* @since 4.2.0 Added `exclude` arg.
*
* @arg $attempt (int) Query by attempt number
* @arg $quiz_id (int|array) Query by Quiz WP post ID (locate multiple quizzes with an array of ids)
* @arg $student_id (int|array) Query by WP User ID (locate by multiple users with an array of ids)
*
* @arg $page (int) Get results by page
* @arg $per_page (int) Number of results per page (default: 25)
* @arg $sort (array) Define query sorting options [id,student_id,quiz_id,start_date,update_date,end_date,attempt,grade,current,passed]
*
* @example
* $query = new LLMS_Query_Quiz_Attempt( array(
* 'student_id' => 1234,
* 'quiz_id' => 5678,
* ) );
*/
class LLMS_Query_Quiz_Attempt extends LLMS_Database_Query {
/**
* Identify the extending query
*
* @var string
*/
protected $id = 'quiz_attempt';
/**
* Retrieve default arguments for a student query
*
* @since 3.16.0
* @since 4.2.0 Added `exclude` default arg.
*
* @return array
*/
protected function get_default_args() {
$args = array(
'student_id' => array(),
'quiz_id' => array(),
'sort' => array(
'start_date' => 'DESC',
'attempt' => 'DESC',
'id' => 'ASC',
),
'status' => array(),
'status_exclude' => array(),
'attempt' => null,
'exclude' => array(),
);
$args = wp_parse_args( $args, parent::get_default_args() );
return apply_filters( $this->get_filter( 'default_args' ), $args );
}
/**
* Retrieve an array of LLMS_Quiz_Attempts for the given result set returned by the query
*
* @since 3.16.0
*
* @return LLMS_Quiz_Attempt[]
*/
public function get_attempts() {
$attempts = array();
$results = $this->get_results();
if ( $results ) {
foreach ( $results as $result ) {
$attempts[] = new LLMS_Quiz_Attempt( $result->id );
}
}
if ( $this->get( 'suppress_filters' ) ) {
return $attempts;
}
return apply_filters( $this->get_filter( 'get_attempts' ), $attempts );
}
/**
* Parses data passed to $statuses
*
* Convert strings to array and ensure resulting array contains only valid statuses.
* If no valid statuses, returns to the default.
*
* @since 3.16.0
* @since 4.2.0 Added `exclude` arg sanitization.
*
* @return void
*/
protected function parse_args() {
// Sanitize post, user, excluded attempts ids.
foreach ( array( 'student_id', 'quiz_id', 'exclude' ) as $key ) {
$this->arguments[ $key ] = $this->sanitize_id_array( $this->arguments[ $key ] );
}
// Validate status args.
$valid_statuses = array_keys( llms_get_quiz_attempt_statuses() );
foreach ( array( 'status', 'status_exclude' ) as $key ) {
// Allow single statuses to be passed in as a string.
if ( is_string( $this->arguments[ $key ] ) ) {
$this->arguments[ $key ] = array( $this->arguments[ $key ] );
}
// Ensure submitted statuses are valid.
if ( $this->arguments[ $key ] ) {
$this->arguments[ $key ] = array_intersect( $valid_statuses, $this->arguments[ $key ] );
}
}
}
/**
* Prepare the SQL for the query.
*
* @since 3.16.0
* @since 6.0.0 Renamed from `preprare_query()`.
*
* @return string
*/
protected function prepare_query() {
global $wpdb;
return "SELECT SQL_CALC_FOUND_ROWS id
FROM {$wpdb->prefix}lifterlms_quiz_attempts
{$this->sql_where()}
{$this->sql_orderby()}
{$this->sql_limit()};";
}
/**
* SQL "where" clause for the query
*
* @since 3.16.0
* @since 3.35.0 Better SQL preparation.
* @since 4.2.0 Added `exclude` arg logic.
*
* @return string
*/
protected function sql_where() {
global $wpdb;
$sql = 'WHERE 1';
foreach ( array( 'quiz_id', 'student_id' ) as $key ) {
$ids = $this->get( $key );
if ( $ids ) {
$prepared = implode( ',', $ids );
$sql .= " AND {$key} IN ({$prepared})";
}
}
// Add attempt lookup.
$val = $this->get( 'attempt' );
if ( '' !== $val ) {
$sql .= $wpdb->prepare( ' AND attempt = %d', $val );
}
// Add attempt exclude.
$exclude = $this->get( 'exclude' );
if ( $exclude ) {
$prepared = implode( ',', $exclude );
$sql .= " AND id NOT IN ({$prepared})";
}
$status = $this->get( 'status' );
if ( $status ) {
$prepared = implode( ',', array_map( array( $this, 'escape_and_quote_string' ), $status ) );
$sql .= " AND status IN ({$prepared})";
}
$status_exclude = $this->get( 'status_exclude' );
if ( $status_exclude ) {
$prepared = implode( ',', array_map( array( $this, 'escape_and_quote_string' ), $status_exclude ) );
$sql .= " AND status NOT IN ({$prepared})";
}
return apply_filters( $this->get_filter( 'where' ), $sql, $this );
}
}