定制 harishdurga/laravel-quiz 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

harishdurga/laravel-quiz

Composer 安装命令:

composer require harishdurga/laravel-quiz

包简介

Provides Quiz Functionality

README 文档

README

Laravel Quiz

Laravel Quiz

Latest Version on Packagist Total Downloads GitHub Actions

With this package, you can easily get quiz functionality into your Laravel project.

Features

  • Add Topics to Questions, Quizzes and to other Topics
  • Supported Question Types: Multiple Choice, Single Choice, and Fill In The Blank
  • Add your own Question Types and define your own methods to handle them
  • Flexible Negative Marking Settings
  • Flexible Quiz with most of the useful settings (Ex: Total marks, Pass marks, Negative Marking, Duration, Valid between date, Description etc)
  • Any type of User of your application can be a Participant of a Quiz
  • Any type of User, and any number of Users of your application can be Authors (different roles) For a Quiz
  • Generate Random Quizzes (In progress)

Installation

You can install the package via Composer:

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

Usage

Class Diagram

LaravelQuiz

Publish Vendor Files (config, migrations, seeder)

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

If you are updating the package, you may need to run the above command to publish the vendor files. But please take a backup of the config file. Also, run the migration command to add new columns to the existing tables.

Create Topic

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

Create Sub Topics

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

Question Types

A seeder class QuestionTypeSeeder will be published into the database/seeders folder. Run the following command to seed question types.

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

Currently, this package is configured to only handle the following types of questions

  • multiple_choice_single_answer
  • multiple_choice_multiple_answer
  • fill_the_blank

Create a QuestionType:

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

User-Defined Methods To Evaluate The Answer For Each Question Type

Though this package provides three question types you can easily change the method that is used to evaluate the answer. You can do this by updating the get_score_for_question_type property in config file.

'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'
]

But your method needs to have the following signature

/**
 * @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
}

If you need to pass any data to your method then you can pass it as the last $data parameter. When you call the calculate_score() method of QuizAttempt then you can pass the data as the parameter.

Create Question

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

Fetch Questions Of A Question Type

$question_type->questions

Fetch only questions with an option (valid question)

Question::hasOptions()->get()

Attach Topics To Question

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

Question Option

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

Fetch Options Of A Question

$question->options

Create Quiz

$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,
    ]
]);

Attach Topics To A Quiz

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

Topicable

Topics can be attached to a quiz or a question. Questions can exist outside of the quiz context. For example, you can create a question bank which you can filter based on the topics if attached.

Negative Marking Settings

By default negative marking is enabled for backward compatibility. You can disable it by setting the enable_negative_marks to false. Two types of negative marking are supported(negative_marking_type). fixed and percentage. Negative marking value defined at question level will be given precedence over the value defined at quiz level. If you want to set the negative marking value at quiz level, set the negative_mark_value to the value you want to set. If you want to set the negative marking value at question level, set the negative_marks of QuizQuestion to your desired value. No need to give a negative number instead the negative marks or percentage should be given in positive.

Adding An Author(s) To A Quiz

$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

Add CanAuthorQuiz trait to your model and you can get all the quizzes associated by calling the quizzes relation. You can give any author role you want and implement ACL as per your use case.

Add Question To Quiz

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

Fetch Quiz Questions

$quiz->questions

Attempt The Quiz

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

Get the Quiz Attempt Participant

MorphTo relation.

$quiz_attempt->participant

Answer Quiz Attempt

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

A QuizAttemptAnswer belongs to QuizAttempt,QuizQuestion and QuestionOption

Get Quiz Attempt Score

$quiz_attempt->calculate_score()

In case of no answer found for a quiz question which is not optional, a negative score will be applied if any.

Get Correct Option Of A Question

$question->correct_options

Return a collection of QuestionOption.

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

Please refer to unit and features tests for more understanding.

Validate A Quiz Question

Instead of getting total score for the quiz attempt, you can use QuizAttempt model's validate() method. This method will return an array with a QuizQuestion model's id as the key for the assoc array that will be returned. Example:

$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'
  ]
]

To be able to render the user answer and correct answer for different types of question types other than the 3 types supported by the package, a new config option has been added.

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

By keeping the question type id as the key, you can put the path to your custom function to handle the question type. This custom method will be called from inside the validate() method by passing the QuizQuestion object as the argument for your custom method as defined in the config. Example:

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];
    }

As shown in the example your customer method should return an array with two elements the first one being the correct answer and the second element being the user's answer for the question. And whatever the $data you send to the validate() will be sent to these custom methods so that you can send additional data for rendering the answers.

Testing

composer test

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security-related issues, please email durgaharish5@gmail.com instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

Laravel Package Boilerplate

This package was generated using the Laravel Package Boilerplate.

harishdurga/laravel-quiz 适用场景与选型建议

harishdurga/laravel-quiz 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 6.56k 次下载、GitHub Stars 达 173, 最近一次更新时间为 2021 年 07 月 19 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「harishdurga」 「laravel-quiz」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 harishdurga/laravel-quiz 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 harishdurga/laravel-quiz 我们能提供哪些服务?
定制开发 / 二次开发

基于 harishdurga/laravel-quiz 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 6.56k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 173
  • 点击次数: 4
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 173
  • Watchers: 3
  • Forks: 27
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2021-07-19