<?php
/**
* File containing the Tables_Based_Answer_Repository class.
*
* @package sensei
*/
namespace Sensei\Internal\Quiz_Submission\Answer\Repositories;
use DateTimeImmutable;
use DateTimeZone;
use Sensei\Internal\Cache_Prefix;
use Sensei\Internal\Services\Progress_Storage_Settings;
use Sensei\Internal\Quiz_Submission\Answer\Models\Answer_Interface;
use Sensei\Internal\Quiz_Submission\Answer\Models\Tables_Based_Answer;
use Sensei\Internal\Quiz_Submission\Submission\Models\Submission_Interface;
use wpdb;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class Tables_Based_Answer_Repository.
*
* @internal
*
* @since 4.16.1
*/
class Tables_Based_Answer_Repository implements Answer_Repository_Interface {
use Cache_Prefix;
/**
* Cache group for quiz answers.
*
* @since $$next-version$$
*
* @var string
*/
private const CACHE_GROUP = 'sensei_quiz_answers';
/**
* WordPress database object.
*
* @var wpdb
*/
private $wpdb;
/**
* Constructor.
*
* @internal
*
* @param wpdb $wpdb WordPress database object.
*/
public function __construct( wpdb $wpdb ) {
$this->wpdb = $wpdb;
}
/**
* Create a new answer.
*
* @internal
*
* @param Submission_Interface $submission The submission.
* @param int $question_id The question ID.
* @param string $value The answer value.
*
* @return Answer_Interface The answer model.
*/
public function create( Submission_Interface $submission, int $question_id, string $value ): Answer_Interface {
/**
* Filters the submission ID when quiz answer is created.
*
* @hook sensei_quiz_answer_create_submission_id
*
* @since 4.23.1
*
* @param {int} $submission_id The submission ID.
* @param {string} $context The context.
* @return {int} The submission ID.
*/
$submission_id = (int) apply_filters( 'sensei_quiz_answer_create_submission_id', $submission->get_id(), 'tables' );
/**
* Filters the question ID when quiz answer is created.
*
* @hook sensei_quiz_answer_create_question_id
*
* @since 4.23.1
*
* @param {int} $question_id The question ID.
* @return {int} The question ID.
*/
$question_id = (int) apply_filters( 'sensei_quiz_answer_create_question_id', $question_id );
$current_datetime = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
$date_format = 'Y-m-d H:i:s';
$this->wpdb->insert(
$this->get_table_name(),
[
'submission_id' => $submission_id,
'question_id' => $question_id,
'value' => $value,
'created_at' => $current_datetime->format( $date_format ),
'updated_at' => $current_datetime->format( $date_format ),
],
[
'%d',
'%d',
'%s',
'%s',
'%s',
]
);
$answer = new Tables_Based_Answer(
$this->wpdb->insert_id,
$submission_id,
$question_id,
$value,
$current_datetime,
$current_datetime
);
if ( $this->wpdb->insert_id && Progress_Storage_Settings::is_cache_enabled() ) {
$cache_submission_id = (int) apply_filters( 'sensei_quiz_answer_get_all_submission_id', $submission->get_id(), 'tables' );
wp_cache_delete( self::get_prefixed_key( $this->get_cache_key( $cache_submission_id ), self::CACHE_GROUP ), self::CACHE_GROUP );
}
return $answer;
}
/**
* Get all answers for a quiz submission.
*
* @internal
*
* @param int $submission_id The submission ID.
*
* @return Answer_Interface[] An array of answers.
*/
public function get_all( int $submission_id ): array {
/**
* Filters the submission ID when getting all quiz answers.
*
* @hook sensei_quiz_answer_get_all_submission_id
*
* @since 4.23.1
*
* @param {int} $submission_id The submission ID.
* @param {string} $context The context.
* @return {int} The submission ID.
*/
$submission_id = (int) apply_filters( 'sensei_quiz_answer_get_all_submission_id', $submission_id, 'tables' );
$cache_key = $this->get_cache_key( $submission_id );
if ( Progress_Storage_Settings::is_cache_enabled() ) {
$cached = wp_cache_get( self::get_prefixed_key( $cache_key, self::CACHE_GROUP ), self::CACHE_GROUP );
if ( false !== $cached ) {
return $cached;
}
}
$query = $this->wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
"SELECT * FROM {$this->get_table_name()} WHERE submission_id = %d",
$submission_id
);
$answers = [];
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Prepared earlier.
foreach ( $this->wpdb->get_results( $query ) as $result ) {
$answers[] = new Tables_Based_Answer(
$result->id,
$result->submission_id,
$result->question_id,
$result->value,
new DateTimeImmutable( $result->created_at, new DateTimeZone( 'UTC' ) ),
new DateTimeImmutable( $result->updated_at, new DateTimeZone( 'UTC' ) )
);
}
if ( Progress_Storage_Settings::is_cache_enabled() ) {
wp_cache_set( self::get_prefixed_key( $cache_key, self::CACHE_GROUP ), $answers, self::CACHE_GROUP );
}
return $answers;
}
/**
* Delete all answers for a submission.
*
* @internal
*
* @param Submission_Interface $submission The submission.
*/
public function delete_all( Submission_Interface $submission ): void {
/**
* Filters the submission ID when deleting all quiz answers.
*
* @hook sensei_quiz_answer_delete_all_submission_id
*
* @since 4.23.1
*
* @param {int} $submission_id The submission ID.
* @param {string} $context The context.
* @return {int} The submission ID.
*/
$submission_id = (int) apply_filters( 'sensei_quiz_answer_delete_all_submission_id', $submission->get_id(), 'tables' );
$this->wpdb->delete(
$this->get_table_name(),
[
'submission_id' => $submission_id,
],
[
'%d',
]
);
if ( Progress_Storage_Settings::is_cache_enabled() ) {
$cache_submission_id = (int) apply_filters( 'sensei_quiz_answer_get_all_submission_id', $submission->get_id(), 'tables' );
wp_cache_delete( self::get_prefixed_key( $this->get_cache_key( $cache_submission_id ), self::CACHE_GROUP ), self::CACHE_GROUP );
}
}
/**
* Get the cache key for quiz answers by submission.
*
* @since $$next-version$$
*
* @param int $submission_id The submission ID.
* @return string The cache key.
*/
private function get_cache_key( int $submission_id ): string {
return (string) $submission_id;
}
/**
* Get the quiz answers table name.
*
* @return string
*/
private function get_table_name(): string {
return $this->wpdb->prefix . 'sensei_lms_quiz_answers';
}
}