開発:質問エンジン

質問エンジンからのリダイレクト)

Moodleは、質問タイプのプラグインを可能にするためのモジュール構造を持つ強力な質問エンジンを持っています。質問エンジンは、質問のレンダリングと生徒の回答の処理を担当します。これはクイズモジュールによって使用されており、将来的にはレッスンや他のモジュールによって使用される予定です。

歴史的に質問エンジンはクイズモジュールの一部として始まりました。 Moodle 1.6以降、Moodleの別のコアコンポーネントで他のMoodleコンポーネントまたはモジュールで使用できるようになりました。この再構築中に、コードはmod / quiz /からquestion /に移動され、テーブルと関数の名前が変更されました。古いテーブルまたは関数名に 'quiz_'が含まれている場合は、新しいテーブル名または関数名に 'question_'が含まれます。

用語

質問エンジンについて話すとき、それらが異なる意味で使われることができるので混乱を引き起こすことがある特定の用語があります。 Moodleでは、以下で説明する特定の用語を採用しました。

質問

質問は、再利用可能な評価項目を構成する一連の定義(質問名、質問テキスト、可能な回答、採点規則、フィードバックなど)です。それで、それは日常の言語で質問をするものよりはるかに多くを含みます。 QTI仕様の用語では、「質問」はより適切に評価項目と呼ばれるか、または単に「項目」と略されます。

多項選択式の質問や数値式の質問など、さまざまな種類の質問があります。これらはMoodleでは質問タイプと呼ばれています。

バージョン1.5以降、MoodleはQTIで「アダプティブアイテム」とも呼ばれる、いわゆるアダプティブ質問を処理することができます。これらは、生徒の回答に応じていくつかの州を通過することによって生徒と対話する質問です。例えば、間違って答えられたが一般的な間違いのために間違っている可能性がある複雑な数学的質問は、この間違いに対するヒントをユーザに提供し、ペナルティを課し、そしてこの質問に対して2回目の試みを許すことができる。クイズは '適応モード'で実行することができます。その場合、Moodleは各質問を個別にマークするためのボタンを提供します。

答え

Moodleでは、 ' 回答'という用語は、 教師が定義した質問の回答に対してのみ使用されます 。これらの教師が定義した答えと、生徒が実際に出す答えとを混同するのは簡単です。そこで私たちは、生徒が提供した回答を「回答」と呼び、教師が定義した回答に適用するために「回答」という用語を予約するという規約を採用しました。教師提供の回答に頼る質問タイプでは、これらは生徒の回答と比較することによって評定プロセスで使用されます。もちろん、すべての質問タイプが教師定義の回答を使用するわけではありませんが、生徒の回答を処理するためのより知的な方法を使用しています。

おそらく、「正解」という意味で「答え」が常に使用されるわけではないことも強調しておくべきでしょう。例えば、多肢選択問題のあらゆる選択肢は答えと呼ばれます。他のシステムは間違った答えのために 'ディストラクタ'という用語を使用します。

Moodleでは常に質問に対する生徒の回答を指すために ' 回答'という用語を使用しています。この用語は常に複数形で使用されますが、質問タイプによっては可能な回答が1つしかありません。

残念ながら、歴史的な理由から、上記の規則の1つの例外があります。question_statesテーブルには、実際には学生の回答を保持することを目的とした「回答」というフィールドがあります。

試み

Moodleでは、「 試み」という用語は「クイズを試みる」(または質問を含む別の活動)という意味で使用されています。クイズの設定によっては、生徒はクイズを何回か試みることができます。生徒が試行ページの対応するボタンをクリックすると、試行は終了します。学生は1回の訪問で試みを完了する必要はありません。彼らはクイズページから離れてナビゲートして後で同じ試みを続けることができます。

質問エンジンを使用する各モジュールは、それ自身のテーブルに試行のための独自のデータを保持する必要があります。モジュールが質問エンジン機能を呼び出すとき、それはしばしば試みオブジェクトを渡すことが期待される。

1つの同じクイズの試行内で、少なくともquestiontypeがそれを許可し、クイズがアダプティブモードで設定されている場合、生徒は特定の質問に答えることを何回か試みることができます。これらは常に「 質問セッション」と呼ばれることもあれば、「試行と呼ばれることはありません。

セッション、州、イベント

新しい試みが開始されると、質問ごとに新しいセッションが開始されます。したがって、ある意味でのセッションは、クイズ全体に対する試みとは何かという問題です。質問セッションは1回の試行よりも長く続きません。また、各質問に対して、1回の試行内に1回のセッションでしか参加できません。

Moodleは学生が1つのセッション内で繰り返し質問と対話することを可能にし、そのような各対話は新しい状態につながります。最初の状態は、セッションが作成されたときに作成されます。生徒が回答を保存、検証、または送信すると、新しい状態が作成されます。生徒の回答、および適切な場合は、回答処理(採点)の結果は、作成された新しい状態に格納されます。

特定の状態の作成につながったイベントの種類は、状態と共に保存されます。現在使用されているイベントの種類は次のとおりです。

開いた
新しいセッションが作成されたばかりで、これが開始状態です。通常、それはまだ生徒の回答を保持していません( 'tryonlast'オプションが設定されているためにクイズの試行が前回の試行に基づいている場合を除く)。
保存する
生徒は保存ボタンをクリックしました。
検証
生徒は自分の回答を検証するよう求めました。これは、それらが有効な応答であることが確認されることを意味します。何らかの線形形式での数式の入力を必要とする数学的な質問の場合、質問タイプは検証された結果をタイプセット形式で生徒に表示したい場合があります。同様のことが他の主題固有の質問タイプにも当てはまるかもしれません。生徒の回答が無効であることが判明した場合、生徒にはその旨が伝えられますが、ペナルティは適用されません。無効な応答は状態とともに格納されます。
グレード
学生は送信ボタンを押しました。等級が計算され、試行とともに保存されます。
重複グレード
生徒は送信ボタンを押しましたが、この質問に対する回答は実際には変更されていません。これは、生徒が1つの質問に対してのみ回答を変更した可能性がある1ページに複数の質問があるクイズでよく起こります。この種のイベントによって作成された状態はデータベースに格納されないと思います。
閉じる
現在クローズされているセッションの最後の状態。現在のところ、セッションはセッションが終了したときにのみ終了します。これは、学生が要求したか、または時間制限が経過したためです。

他のイベントタイプを導入する予定です

提出する
生徒はグレーディングに対する回答を送信しましたが、グレーディングはまだ行われていません。これは、例えばエッセイの質問のように、先生がマークした質問タイプによって使用されます。

コード文書

コードはPHPドキュメントの規約に従って文書化されています。このWikiの説明は、これを補足するものです。

インラインコメントはコード内で自由に使用する必要があります。以下の規約は、特別な意味を持つコメントの検索を容易にします。

  • やるべきことについてのコメントにTODOを使う
  • つかいます ???コードに関する質問であるコメントに

コードはパッケージにまとめられています

  • パッケージquestionbank - 質問バンクシステムに関連するコード
    • サブパッケージquestiontypes - 質問タイプ基本クラスを含む質問タイプに関連するコード。
    • サブパッケージimportexport - 質問のインポートとエクスポートに関連するコード。

一般に、基本クラスdefault_questiontypeとqformat_defaultには、ほとんどのドキュメントタイプが含まれています。これは、すべての質問タイプが同じインタフェースに従うためです。さまざまなサブクラスすべてに同じ情報を繰り返しても意味がありません。サブクラスは、基本クラスから派生していない新しいメソッドの記述に集中する必要があります。

良いコメントを書くためのより多くのアドバイスについてはPHPdocumentorマニュアルを見てください。

MoodleのPHPドキュメントは、 http ://phpdocs.moodle.org/にあります。

API

ライブラリlib / questionlib.phpには、質問を使用したいモジュールで利用できる必要があるすべての関数が含まれています(これはMoodle 1.6の新機能です。Moodle1.5では、これはmod / quiz / locallib.phpの一部でした)。このライブラリをロードすると、questiontype.phpファイルをロードすることによってすべてのquestiontypeクラスがインスタンス化されます。

APIの説明はまだ書かれている必要があります。また、lib / questionlib.phpもAPI関数とヘルパー関数を区別するために少し整理する必要があります。

組織

デフォルトの質問タイプクラスはquestion / type / questiontype.phpで定義されています(Moodle 1.5ではこれはまだmod / quiz / locallib.phpにありました)。個々の質問タイプはそれ自身のquestiontype.phpファイルでこのクラスを拡張します。質問タイプクラスのドキュメントについては、デフォルトの質問タイプのドキュメントをよく見てください。デフォルトクラスのドキュメントの多くは他の質問タイプクラスでは繰り返されていないためです。

質問タイプはクラスとして実現されていますが、質問エンジンは本当にオブジェクト指向の方法で書かれていません。その代わりに、データベースレコードを保持するための配列の代わりとしてのみオブジェクトを使用するというMoodleモデルに従います。そのため、モジュール内で中心的な役割を果たす質問、試行、および状態オブジェクトにはメソッドがありません。 questiontypeオブジェクトだけがメソッドを持ちます。奇妙なことに、クイズモジュールは最初に各questiontypeクラスの1つのオブジェクトをインスタンス化して、それから異なる質問にそれらのメソッドを再利用します。 Moodleのプログラミング方法に慣れている場合は、これで十分に対処できます。

オブジェクトとデータ構造

質問エンジンがどのように機能するかを理解するための鍵は、さまざまな種類のオブジェクトがどのように連携して機能するかを理解することです。最も重要なものは以下のとおりです。

  • 質問
  • 試み

質問は教師によって作成されたデータです。試行回数と状態は、クイズと対話するときに学生によって作成されたデータです。

Moodleクイズモジュールを使用すると、生徒はクイズで複数回試すことができます。このような試行に関するデータは、試行オブジェクトに格納されています。 Moodle質問エンジンはそのような試みに対処するように最適化されており、したがって質問エンジンを使用したいすべてのモジュールは試行オブジェクトを実装し、それを多くの質問エンジン機能に渡す必要があります。試みオブジェクトは、例えば、この試みに対してどのようにクイズが無作為化されたか、および質問と回答の順序付けに関する情報を保持します。

Moodleでは、生徒は単一の質問で繰り返し対話することができます。したがって、たとえば、学生は最初に答えを保存し、後でそれをマークし、それから正しくないとマークされた場合はそれを修正することができます。学生が特定の試行内で最初に質問を見ると、 質問セッションと最初の質問状態が作成されます。生徒が質問と対話するたびに、新しい質問状態が作成されます。そのため、状態はユーザーID、試行ID、および質問IDによって索引付けされます。

データベース構造

これらすべてのデータはMoodleのデータベースに保存する必要があります。これがどのように達成されるかは、役に立つ図表も含まれているクイズデータベース構造についての別のページで説明されています。

Moodleで慣習的であるように、ほとんどのランタイムオブジェクトは単に特定のデータベースレコードからのデータを表します。したがって、たとえば$ quizオブジェクトには、 クイズテーブルのすべてのフィールドに対応するフィールドがあります 。場合によっては、オブジェクトには実行時に追加される追加のフィールドがいくつかあります。これは特に$ questionおよび$ stateオブジェクトに当てはまります。これらの追加フィールドは、 クイズデータベース構造に関するページにも記載されています。これらのオブジェクトを処理するために使用される多くの機能は追加のフィールドを利用するため、これらのオブジェクトを作成するために正しい機能を使用する必要があります。

ランタイムオブジェクト

クイズモジュールによって使用されるいくつかのオブジェクトは純粋にランタイムオブジェクトであり、データベーステーブルに対応しません。これらのオブジェクトの構造は、 Quizランタイムオブジェクトに関する別のページで詳細に説明されています

クイズモジュールの主なスクリプトはattempts.phpで、これらすべてのオブジェクトを処理する必要があります。 attempts.php説明を勉強することは、したがって、クイズモジュールのコードを勉強し始めるための良い方法です。

応答ストレージ

質問に対する生徒の回答はに保存されます。
 $ state->レスポンス
。質問タイプは、彼らが望む方法で彼らの応答(そして他の状態情報)の保存メカニズムを完全に自由に実装することができます。それでも、標準的な質問タイプはすべて同様のモデルに従います。デフォルトの格納モデルと質問タイプ特有のバリエーションは以下で説明されます。質問タイプが自由に回答記憶メカニズムを選択し、記憶モデルから実行時モデルに変換する柔軟性は、実行時の初期化を可能にする3つの関数のセットによって提供されます。
 $ state->レスポンス
ランタイムからストレージモデルへの変換、およびその逆の変換を行うフィールド。
 create_session_and_responses() 
$ stateオブジェクトを初期化します。特に
 $ state->レスポンス
フィールド
 restore_session_and_responses() 
質問タイプ固有のセッションデータをデータベースから
 $ state 
オブジェクト、特に指定されたオブジェクト用に保存されたレスポンスをロードします。
 $ state 
 $ state->レスポンス
フィールド。
 save_session_and_responses() 
質問タイプ固有のセッションデータを$ stateオブジェクトからデータベースに保存します。特に、ほとんどの質問タイプでは、からの回答が保存されます。
 $ state->レスポンス
データベースに。
一般クイズモジュールのコードは、
 $ state-> responds [''] 
quiz_statesテーブル内の回答フィールドに追加し 、このフィールドの内容を自動的に
 $ state-> responds [''] 
。これは、応答として単一の値しか期待しない質問タイプは、上記の3つのメソッドの実装をスキップできることを意味します。多値回答を持つすべての質問タイプは、これらのメソッドを実装する必要があります。デフォルトの質問タイプは、quiz_statesテーブルの回答フィールドへの/からの回答をシリアライズ/デシリアライズすることによってこの問題を処理します。ただし、質問タイプ固有のテーブルでquiz_statesテーブルを拡張する、つまり質問タイプ固有のテーブルの外部キーとしてquiz_statesレコードのIDを使用することも可能です(そしてより良い方法かもしれません)。の値が
 $ state-> responds [''] 
回答フィールドの値に設定され、回答を直列化する質問タイプは上書きする必要があります。
 save_session_and_responses() 
)一般的なコードがシリアル化した値でこのフィールドを設定する値(通常は単純なset_fieldで達成される)。方法では
 restore_session_and_responses() 
シリアル化された値はから読み取ることができます
 $ state-> responds [''] 
これは、quiz_statesテーブルのanswerフィールドからの値が移動された場所であるためです。この配列値が設定解除されるか、配列全体が上書きされるように注意する必要があります。これにより、配列に誤って空の文字列インデックスを持つ値が含まれることはありません。

応答処理

レスポンスの実行時モデルは$ state->レスポンス配列の構造を決定します。フォームの要素の名前から始めて、このセクションは関連する処理ステップを通り抜けます、そしてそれ故になぜ$ state->レスポンス配列のキーが異なる質問タイプのために異なることができるかを明確にすることを試みます。さらに、配列キーの選択方法と設定方法についても説明しています。

最初はフォームフィールドの命名規則から始めるのは奇妙に思えるかもしれませんが、その理由は後で明らかになります。質問のコントロール(すなわちフォームフィールド)はメソッドによって出力されます。
 print_question_formulation_and_controls() 
。規則では、制御要素の名前はの値で始まっていなければならないと規定されているだけです。
 $ question-> name_prefix 
。の
 $ question-> name_prefix 
"resp"で始まり、その後に質問IDとアンダースコアが続く文字列です。
 resp56_ 
。デフォルトの場合、コントロール要素が1つだけの場合(これには、同じ名前のラジオボタンのリストの場合も含まれます)、名前の接頭辞には後置記号は追加されません。複数のフォーム要素を許可または要求する質問タイプの場合、名前プレフィックスに任意の文字列を追加してこれらのフォーム要素の名前を形成できます。接尾辞には、リレーショナルデータ(つまり、quiz_answersテーブル内のレコードのID)を含めないでください。これは、バージョン付き質問のグレード変更に関する問題を引き起こす可能性があるためです。質問が印刷された後、サーバーは質問が送信されたときにのみ再度表示されます。そのため、送信されたデータには、で始まる文字列でインデックス付けされたいくつかの値が含まれます。
 respXX_ 
。提出時に、機能
 quiz_process_responses() 
これは、投稿キー(つまり、アンダースコアの後の部分)を配列キーとして使用して、投稿された回答をid XXの質問の状態に割り当てます。コントロール要素が1つしかないデフォルトの場合、名前は名前の接頭辞のみで構成されます。これはなぜデフォルトのインデックスが
 $ state->レスポンス
arrayは空の文字列です。各配列要素の値は、明らかにフォームによって送信された値、基本的には生の応答です。関数
 quiz_process_responses() 
次に質問タイプ固有のメソッドを呼び出します。
 grade_responses() 
提出された回答に評点を割り当てる
 compare_responses() 
回答が前回の提出と同一であったかどうかを判断し、同じ回答を繰り返しグレード変更しないようにします。これらの質問タイプ特有の機能は、の予想されるキーを知っている必要があります。
 $ state->レスポンス
アレイ。最後に、メソッド
 restore_session_and_responses() 
そして
 save_session_and_responses() 
また、の質問タイプ固有のレイアウトを知る必要があります。
 $ state->レスポンス配列
そして、例えばデータ表現からまたはデータ表現へ変換することによって、情報を復元または保存する。

質問の種類

Template:Questiontype developer docsクイズモジュールはそれ自体がモジュール式で、質問タイプのプラグインを可能にします。それぞれの質問タイプについて、右側のメニューからアクセスできるページがあるはずです。そこには、少なくとも以下についての詳細が記載されています。

  • データベーステーブル
  • 応答ストレージ
  • 質問オプションオブジェクト
  • 状態オプションオブジェクト

開発:質問タイプコードフロー

今後、Moodlersが多くのノンコア質問タイプに貢献することが望まれます。そのためには、 How to the write typeプラグインを始めるのがよいでしょう。

等級

グレードの取り扱いは少し複雑です。なぜなら、周りにはさまざまなグレードがあり、さまざまな方法でスケール変更および結合されるからです。このセクションでは、これがどのように行われるのか、そしてその理由を要約する必要があります。

次の成績項目が使用されています。

  • $ question-> defaultgrade
これは、この質問の最大評点のデフォルト値です。教師が質問を作成し、それがquiz_questionsテーブルのint(10)フィールドに格納されると、これが設定されます。しかし、質問が実際に特定のクイズで使用されている場合、教師はこのデフォルトを無効にすることができ、これは次の場所に保存されます。
  • $ question-> maxgrade
これは、現在のクイズとの関連で教師がこの質問に割り当てた最高評点です。これはデフォルトで$ questions-> defaultgradeと同じですが、教師はクイズを編集するときにこれを変更できます。データベースでは、それはquiz_question_instancesテーブルの int(10)フィールドに格納されます
  • $ question->ペナルティ
  • $ state-> raw_grade
  • $ state-> grade
  • $ state->ペナルティ
  • $ state-> sumpenalty
  • $ try-> sumgrades

教師が設定した最大評点、$ question-> defaultgradeおよび$ question-> maxgradeは整数です。学生が取得するすべての学年は原則として浮動小数点数です。歴史的な理由から、それらはvarchar(10)フィールドとしてデータベースに格納されています。データベースへの書き込み時には、すべてのグレードが正しく丸められて10文字以下の文字列になるように注意する必要があります。そうしないと、データベースへの書き込みが失敗します。バグ4220を参照してください。

特定のクイズでのユーザーの評点の計算の最終結果は、 quiz_gradesテーブルの 'grade'フィールドに格納されています 。このフィールドのタイプはdoubleです。

ペナルティメカニズム

それは何のためにあるのか

クイズがアダプティブモードで実行されると、生徒は繰り返し質問と対話することができます。そのため、特に生徒は間違った答えを受け取ったときにもう一度試すことができます。明らかに質問の最後の印は、学生がもともとそれを正しく得なかったという事実を反映していなければなりません。したがって、最終マークからペナルティが差し引かれます。

ペナルティの決定方法

まず第一に、クイズが適応モードで実行されている場合にのみ関連します。この場合のみ、生徒は2回目の試行を行うことができます。したがって、このモードでのみペナルティを差し引くことができます。

アダプティブモードでも、ペナルティメカニズムはクイズオプションで選択されている場合にのみ使用されます。 「ペナルティの適用」が「いいえ」に設定されている場合、質問の最後のマークは最後の採点された回答のマークです。

各質問には、0から1までの数値である「ペナルティ」フィールド(実際には「ペナルティファクタ」と呼ぶ必要があります)があります。誤った回答に対するペナルティは、積($ quiz->ペナルティ* $ quiz-> grade)として計算されます。つまり、質問に対して達成可能な最大評点を持つペナルティ要因の積として。この商品は$ state->ペナルティで保存されています。そのため、$ quiz->ペナルティは、それぞれの誤った回答に対するペナルティとして差し引かれる最大評点の割合です。

データベースとmod / quiz / defaults.phpの両方で、$ quiz->ペナルティフィールドのデフォルト値は0.1です。もちろん、このデフォルトはクイズ設定ページで管理者によって上書きされる可能性があります。この管理者が選択したデフォルトは(通常の管理者のデフォルトと同様に)$ CFG-> quiz_penaltyに格納されています。教師は、質問を追加または編集するときに、質問ごとに異なるペナルティ係数を選択できます。 (Moodle 1.8では、デフォルト値0.1が実際にはmoodle / question / type / edit_question_form.phpの87行目にハードコードされています)

生徒が間違った試みを繰り返す(または部分的に正しい試みをする)と、これらすべての試みに対するペナルティは$ state-> sumpenaltiesに加算されます。質問のマークは、最後の採点された回答のマークからペナルティの合計を引いたものとして計算されます。

$ state-> sumpenaltiesに関する奇妙な事実の1つは、効率上の理由から、それはquiz_statesテーブルには格納されず、代わりにquiz_newest_statesテーブルの 'sumpenalty'フィールドに格納されることです。そうすれば、応答ごとに1回ではなく、試行ごとに1回だけ格納する必要があります。

コードのどこで行われているか

関数quiz_apply_penalty_and_timelimit()は、$ state-> raw_gradeの生の等級から$ state-> sumpenaltyのペナルティを引いて、応答の$ state-> gradeを取得します。しかしながら、その問題に対する新しい試みの成績が以前に達成された成績を決して下回らないことが保証されています。この関数は$ state-> sumpenaltyを$ state->ペナルティの量だけ増やします。仮定は、$ state->ペナルティがこの関数を呼び出すコードによって適切に設定されたことです(例:quiz_process_responses)。

質問に属するファイル

これは、Moodle 2.0ファイルAPIに関連した状況について説明しています。

ファイル領域

各質問にはさまざまなファイル領域があります。

たとえば、「question」コアコンポーネントに属する「questiontext」というファイルがあります。このコンポーネントには、質問テキストで使用される画像やその他の埋め込みファイルが格納されています。 'generalfeedback'と 'question_answer'ファイル領域もあります。

各質問タイプに固有のいくつかのファイル領域もあります。たとえば、 'qtype_multichoice'コンポーネントには、(とりわけ) 'correctfeedback'ファイル領域があります。

これらのファイル領域はすべて$ question-> categoryのコンテキストであるコンテキストに属しています。

ファイルの提供とアクセスチェック

ファイルは質問システムまたは特定の質問タイプに属していますが、ユーザーが特定のファイル(一般的なフィードバックの画像など)を見ることができるかどうかは、Moodleのどの部分によっても影響を受けるためです。質問を使用している(たとえば、クイズモジュールや質問のプレビュー)。

説明する最も簡単な方法は、おそらく特定の画像が表示されているかどうかを判断するためのコールスタックを表示することです。その後、コードを読みに行くことができます。

クイズの試みで質問のquestiontext内の画像のための要求... / pluginfile.php / 123 / question / questiontext / 234/345 / image.png。

(ここで、123はコンテクストIDであり、トリプチド(question_attempts.idに対応)の場合は234、そしてクエスチョンIDは345です。)

  1. pluginfile.php
  2. lib / questionlib.phpの question_pluginfile()
  3. mod / quiz / lib.phpの quiz_question_pluginfile()
  4. mod / quiz / attemptslib.php内の quiz_attempt-> check_file_access()
  5. lib / questionlib.phpの question-> check_file_access()
  6. qtype_ どんな - > check_file_access() 質問/タイプ/何/ quetsiontype.phpで

その代わりに、質問が質問プレビューポップアップウィンドウに表示されていた場合、コールスタックは次のようになります。

  1. pluginfile.php
  2. lib / questionlib.phpの question_pluginfile()
  3. question / previewlib.phpの question_preview_question_pluginfile()
  4. lib / questionlib.phpの question-> check_file_access()
  5. qtype_ どんな - > check_file_access() 質問/タイプ/何/ quetsiontype.phpで

(異なるビットは太字で強調表示されています)。

代わりに、画像のURLが... / pluginfile.php / 123 / qtype_multichoice / correctfeedback / 234/345 / image.pngの場合、コールスタックは次のようになります。

  1. pluginfile.php
  2. 問題のqtype_multichoice_pluginfile() / type / multichoice / lib.php
  3. lib / questionlib.phpの question_pluginfile()
  4. mod / quiz / lib.phpの quiz_question_pluginfile()
  5. mod / quiz / attemptslib.php内の quiz_attempt-> check_file_access()
  6. lib / questionlib.phpの question-> check_file_access()
  7. 問題のqtype_multichoice-> check_file_access() / type / multichoice / quetsiontype.php

大まかに言って、qtype_whatever-> check_file_access()はprint_question_formulation_and_controlsと同じ$ question、$ stateおよび$ optionsオブジェクトをとるので、たとえば、フィードバックでファイルにアクセスしようとしたときと同じパーミッションチェックを行うことができます。フィードバックを表示するかどうか。

quiz_question_pluginfile関数またはquestion_preview_question_pluginfile関数は、URL内の$ tryptidおよび$ questionidに基づいて正しい$ question、$ state、$ optionsを取得します。彼らはまたいくつかの基本的なアクセスチェックを行います。

他のすべての機能は、実際には処理するのに適切な場所に要求をディスパッチすることだけです。