harishdurga/laravel-quiz

提供测验功能

v2.0.0 2024-08-17 15:59 UTC

README

Laravel Quiz

Laravel Quiz

Latest Version on Packagist Total Downloads GitHub Actions

使用此包,您可以轻松将测验功能集成到您的Laravel项目中。

特性

  • 将主题添加到问题、测验和其他主题
  • 支持的题型:单选、多选和填空题
  • 添加您自己的题型并定义处理它们的自定义方法
  • 灵活的负分设置
  • 灵活的测验,具有大多数有用设置(例如:总分、及格分、负分、时长、有效日期、描述等)
  • 您的应用程序的任何类型用户都可以成为测验的参与者
  • 您的应用程序的任何类型用户,以及任何数量的用户都可以成为测验的作者(不同角色)
  • 生成随机测验(进行中)

安装

您可以通过Composer安装此包

composer require harishdurga/laravel-quiz
  • Laravel版本:9.X
  • PHP版本:8.X

用法

类图

LaravelQuiz

发布供应商文件(配置、迁移、生成器)

php artisan vendor:publish --provider="Harishdurga\LaravelQuiz\LaravelQuizServiceProvider"

如果您正在更新包,您可能需要运行上述命令以发布供应商文件。但请备份配置文件。此外,运行迁移命令以向现有表添加新列。

创建主题

$computer_science = Topic::create([
    'name' => 'Computer Science',
    'slug' => 'computer-science',
]);

创建子主题

$algorithms = Topic::create([
    'name' => 'Algorithms',
    'slug' => 'algorithms'
]);
$computer_science->children()->save($algorithms);

题型

将一个名为 QuestionTypeSeeder 的生成器类发布到 database/seeders 文件夹。运行以下命令以生成题型。

php artisan db:seed --class=\\Harishdurga\\LaravelQuiz\\Database\\Seeders\\QuestionTypeSeeder

当前,此包配置为仅处理以下类型的题目

  • multiple_choice_single_answer
  • multiple_choice_multiple_answer
  • fill_the_blank

创建题型

QuestionType::create(['name'=>'select_all']);

为每种题型定义用户自定义方法以评估答案

尽管此包提供了三种题型,您可以轻松更改用于评估答案的方法。您可以通过更新配置文件中的 get_score_for_question_type 属性来实现这一点。

'get_score_for_question_type' => [
    1 => '\Harishdurga\LaravelQuiz\Models\QuizAttempt::get_score_for_type_1_question',
    2 => '\Harishdurga\LaravelQuiz\Models\QuizAttempt::get_score_for_type_2_question',
    3 => '\Harishdurga\LaravelQuiz\Models\QuizAttempt::get_score_for_type_3_question',
    4 => 'Your custom method'
]

但您的方法需要以下签名

/**
 * @param QuizAttemptAnswer[] $quizQuestionAnswers All the answers of the quiz question
 */
public static function get_score_for_type_3_question(QuizAttempt $quizAttempt, QuizQuestion $quizQuestion, array $quizQuestionAnswers, $data = null): float
{
    // Your logic here
}

如果您需要向方法传递任何数据,则可以将它作为最后一个 $data 参数传递。当您调用 QuizAttemptcalculate_score() 方法时,您可以传递数据作为参数。

创建问题

$question_one = Question::create([
    'name' => 'What is an algorithm?',
    'question_type_id' => 1,
    'is_active' => true,
    'media_url' => 'url',
    'media_type' => 'image'
]);

获取某个题型的题目

$question_type->questions

仅获取带选项的问题(有效问题)

Question::hasOptions()->get()

将主题附加到问题

$question->topics()->attach([$computer_science->id, $algorithms->id]);

问题选项

$question_two_option_one = QuestionOption::create([
            'question_id' => $question_two->id,
            'name' => 'array',
            'is_correct' => true,
            'media_type'=>'image',
            'media_url'=>'media url'
        ]);

获取问题的选项

$question->options

创建测验

$quiz = Quiz::create([
    'name' => 'Computer Science Quiz',
    'description' => 'Test your knowledge of computer science',
    'slug' => 'computer-science-quiz',
    'time_between_attempts' => 0, //Time in seconds between each attempt
    'total_marks' => 10,
    'pass_marks' => 6,
    'max_attempts' => 1,
    'is_published' => 1,
    'valid_from' => now(),
    'valid_upto' => now()->addDay(5),
    'media_url'=>'',
    'media_type'=>'',
    'negative_marking_settings'=>[
        'enable_negative_marks' => true,
        'negative_marking_type' => 'fixed',
        'negative_mark_value' => 0,
    ]
]);

将主题附加到测验

$quiz->topics()->attach([$topic_one->id, $topic_two->id]);

Topicable

主题可以附加到测验或问题。问题可以存在于测验上下文之外。例如,您可以创建一个问题库,您可以基于附加的主题进行筛选。

负分设置

默认情况下,为了向后兼容,负分标记已启用。您可以通过将 enable_negative_marks 设置为 false 来禁用它。支持两种负分标记类型(negative_marking_type):fixedpercentage。在问题级别定义的负分标记值将优先于在测验级别定义的值。如果您想设置测验级别的负分标记值,请将 negative_mark_value 设置为您想要设置的值。如果您想设置问题级别的负分标记值,请将 QuizQuestionnegative_marks 设置为您希望设置的值。不需要给出负数,而是应以正数给出负分或百分比。

将作者添加到测验中

$admin = Author::create(
            ['name' => "John Doe"]
        );
$quiz = Quiz::factory()->make()->create([
            'name' => 'Sample Quiz',
            'slug' => 'sample-quiz'
        ]);
QuizAuthor::create([
            'quiz_id' => $quiz->id,
            'author_id' => $admin->id,
            'author_type' => get_class($admin),
            'author_role' => 'admin',
        ]);
$quiz->quizAuthors->first()->author; //Original User

CanAuthorQuiz 特性添加到您的模型中,然后您可以通过调用 quizzes 关系来获取所有关联的测验。您可以赋予任何作者角色,并根据您的用例实现访问控制列表(ACL)。

将问题添加到测验中

$quiz_question =  QuizQuestion::create([
    'quiz_id' => $quiz->id,
    'question_id' => $question->id,
    'marks' => 3,
    'order' => 1,
    'negative_marks'=>1,
    'is_optional'=>false
]);

获取测验问题

$quiz->questions

尝试测验

$quiz_attempt = QuizAttempt::create([
    'quiz_id' => $quiz->id,
    'participant_id' => $participant->id,
    'participant_type' => get_class($participant)
]);

获取测验尝试参与者

MorphTo 关系。

$quiz_attempt->participant

回答测验尝试

QuizAttemptAnswer::create(
    [
        'quiz_attempt_id' => $quiz_attempt->id,
        'quiz_question_id' => $quiz_question->id,
        'question_option_id' => $question_option->id,
    ]
);

QuizAttemptAnswer 属于 QuizAttemptQuizQuestionQuestionOption

获取测验尝试分数

$quiz_attempt->calculate_score()

如果没有找到非必答题的答案,将应用负分。

获取问题的正确选项

$question->correct_options

返回一个 QuestionOption 集合。

public function correct_options(): Collection
{
    return $this->options()->where('is_correct', 1)->get();
}

请参考单元测试和功能测试以了解更多信息。

验证测验问题

您可以使用 QuizAttempt 模型的 validate() 方法来获取测验尝试的总分,而不是使用该方法。此方法将返回一个数组,其中 QuizQuestion 模型的 id 作为关联数组返回的键。 示例:

$quizAttempt->validate($quizQuestion->id); //For a particular question
$quizAttempt->validate(); //For all the questions in the quiz attempt
$quizAttempt->validate($quizQuestion->id,$data); //$data can any type
[
  1 => [
    'score' => 10,
    'is_correct' => true,
    'correct_answer' => ['One','Five','Seven'],
    'user_answer' => ['Five','One','Seven']
  ],
  2 => [
    'score' => 0,
    'is_correct' => false,
    'correct_answer' => 'Hello There',
    'user_answer' => 'Hello World'
  ]
]

为了能够渲染除包支持的3种问题类型之外的其他类型的问题的答案,已添加了一个新的配置选项。

'render_answers_responses'    => [
        1  => '\Harishdurga\LaravelQuiz\Models\QuizAttempt::renderQuestionType1Answers',
        2  => '\Harishdurga\LaravelQuiz\Models\QuizAttempt::renderQuestionType2Answers',
        3  => '\Harishdurga\LaravelQuiz\Models\QuizAttempt::renderQuestionType3Answers',
    ]

通过将问题类型ID作为键,您可以将处理问题类型的自定义函数的路径放入其中。此自定义方法将在 validate() 方法内部通过传递配置中定义的自定义方法的参数 QuizQuestion 对象调用。 示例:

public static function renderQuestionType1Answers(QuizQuestion $quizQuestion,QuizAttempt $quizAttempt,mixed $data=null)
    {
        /**
         * @var Question $actualQuestion
         */
        $actualQuestion = $quizQuestion->question;
        $answers = $quizQuestion->answers->where('quiz_attempt_id', $quizAttempt->id);
        $questionOptions = $actualQuestion->options;
        $correctAnswer = $actualQuestion->correct_options()->first()?->option;
        $givenAnswer = $answers->first()?->question_option_id;
        foreach ($questionOptions as $questionOption) {
            if ($questionOption->id == $givenAnswer) {
                $givenAnswer = $questionOption->option;
                break;
            }
        }
        return [$correctAnswer, $givenAnswer];
    }

如示例所示,您的自定义方法应返回一个包含两个元素的数组,第一个元素是正确答案,第二个元素是问题的用户答案。发送给 validate() 的任何 $data 都将发送到这些自定义方法,以便您可以为渲染答案发送附加数据。

测试

composer test

变更日志

请参阅 CHANGELOG 了解最近更改的信息。

贡献

请参阅 CONTRIBUTING 了解详细信息。

安全

如果您发现任何安全相关的问题,请通过电子邮件 durgaharish5@gmail.com 反馈,而不是使用问题跟踪器。

致谢

许可证

MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件

Laravel 包模板

此包是使用 Laravel 包模板 生成的。