開発情報・ナレッジ

投稿者: ShiningStar株式会社 2024年5月16日 (木)

正誤判定と点数計算ができるテストフォームのサンプル

この記事では登録フォームブロックを使って知識テストの様なテストフォームを作成するサンプルをご紹介します。
点数計算をし、最後に出力及びDBへの記録もします。


全体像

機能
完了ステップにて正答か誤答か判定をしてその結果を出力します。
テストの点数配当を設定し、何点獲得したかをDBに記録します。
手順
正解と不正解の表示を含むHTMLを完了ステップに追加します。
PHPでテスト結果を判定し、それをHTMLに渡すようにコードを記述します。
テストの点数配当と結果のDBへの記録をPHPで処理します。

DB設定

上記の様に一問ずつ設問のフィールドを作成してください。
本サンプルにつきましては全てセレクトかつラジオボタンにて作成しています。
誰が答えたか分かる様に参照フィールドでマスタDBのユニークIDとなる値を追加してください。
scoreという識別名の点数フィールドも追加してください。

設定方法

登録フォームブロックをソースデザインで作成してください。
認証エリアを作成してください。
登録フォームブロックが完成したら認証エリア内にページを作成し上記で作成した登録フォームブロックを読み込む様にしてください。

登録フォームブロック 完了ステップ

HTML
    <div class="sp-form-container">
  <div class="sp-form-item sp-form-html" th:inline="none">
    <p><span style="font-size: 18pt;">回答結果</span></p>
  </div>
  <p>あなたのスコアは<span th:text="${cp.result.value['result']}">0</span>点です。</p>
  
  <!-- 1問目(question1) -->
  <p>1問目</p>
  <div class="sp-form-item sp-form-field">
    <div class="sp-form-data">
      <p>あなたの回答結果:
        <span th:text="${record[1]?.label}"
              th:classappend="${record[1]?.label == cp.result.value['question1'] ? 'correct' : 'incorrect'}">
          Item
        </span>
      </p>
      <p>正しい回答結果:<span th:text="${cp.result.value['question1']}">Item</span></p>
    </div>
  </div>

  <!-- 2問目(question2) -->
  <p>2問目</p>
  <div class="sp-form-item sp-form-field">
    <div class="sp-form-data">
      <p>あなたの回答結果:
        <span th:text="${record[2]?.label}"
              th:classappend="${record[2]?.label == cp.result.value['question2'] ? 'correct' : 'incorrect'}">
          Item
        </span>
      </p>
      <p>正しい回答結果:<span th:text="${cp.result.value['question2']}">Item</span></p>
    </div>
  </div>

  <!-- 3問目(question3) -->
  <p>3問目</p>
  <div class="sp-form-item sp-form-field">
    <div class="sp-form-data">
      <p>あなたの回答結果:
        <span th:text="${record[3]?.label}"
              th:classappend="${record[3]?.label == cp.result.value['question3'] ? 'correct' : 'incorrect'}">
          Item
        </span>
      </p>
      <p>正しい回答結果:<span th:text="${cp.result.value['question3']}">Item</span></p>
    </div>
  </div>

  <!-- 4問目(question4) -->
  <p>4問目</p>
  <div class="sp-form-item sp-form-field">
    <div class="sp-form-data">
      <p>あなたの回答結果:
        <span th:text="${record[4]?.label}"
              th:classappend="${record[4]?.label == cp.result.value['question4'] ? 'correct' : 'incorrect'}">
          Item
        </span>
      </p>
      <p>正しい回答結果:<span th:text="${cp.result.value['question4']}">Item</span></p>
    </div>
  </div>

  <!-- 5問目(question5) -->
  <p>5問目</p>
  <div class="sp-form-item sp-form-field">
    <div class="sp-form-data">
      <p>あなたの回答結果:
        <span th:text="${record[5]?.label}"
              th:classappend="${record[5]?.label == cp.result.value['question5'] ? 'correct' : 'incorrect'}">
          Item
        </span>
      </p>
      <p>正しい回答結果:<span th:text="${cp.result.value['question5']}">Item</span></p>
    </div>
  </div>
</div> 
                
適宜設問文やデザイン等はお好みの形に変更してください。

CSS

     .correct { color: green; }
.incorrect { color: red; } 
                

登録フォームブロックのCSSタブに貼り付けてください。
正答だった場合色指定や誤答だった場合の色分けに使います。

PHP

    <?
//------------------------------
// 設定値
//------------------------------
define("API_URL", "https://api.spiral-platform.com/v1");
define("API_KEY", "");
define("APP_ROLE", "");
define("DB_ID", "85957"); //テストDBID
define("APP_ID", "21894"); //テスト結果を格納するDBが属しているアプリID
$registForm = $SPIRAL->getRegistrationForm("quizForm"); //フォームの識別名
$correct_answers = [ //正答ラベル値
    "question1" => "ラベル1",
    "question2" => "ラベル2",
    "question3" => "ラベル3",
    "question4" => "ラベル1",
    "question5" => "ラベル2"
];
// 正解の配列とそれぞれの点数
    $questions = [
        'question1' => ['answer' => 1, 'points' => 20],
        'question2' => ['answer' => 2, 'points' => 20],
        'question3' => ['answer' => 3, 'points' => 20],
        'question4' => ['answer' => 1, 'points' => 20],
        'question5' => ['answer' => 2, 'points' => 20]
    ];

//step2での画像表示
$step = $registForm->getStep();
if($step == 1){
    
}

//完了ステップでの回答表示
if($registForm->isCompletedStep()){
//正答ラベル出力用
$SPIRAL->setTHValues($correct_answers);

//点数計算
$record = $SPIRAL->getRecordValue();
// スコアの計算
$totalScore = 0;

    foreach ($questions as $question => $data) {
        if (isset($record['item'][$question]) && $record['item'][$question] == $data['answer']) {
            $totalScore += $data['points'];
        }
    }

    // スコアをDBに保存
    $commonBase = CommonBase::getInstance();
    $UpdateData = [
        'score' => strval($totalScore)
    ];
    
    $resultRecordUpdate = $commonBase->apiCurlAction("PATCH", "/apps/". APP_ID. "/dbs/". DB_ID. "/records/". $record['item']['_id'], $UpdateData);

    // 結果をthymeLeafに設定
    $SPIRAL->setTHValue("result", $totalScore);
} else {
    $SPIRAL->setTHValue("result", "null");
}


//------------------------------
// 共通モジュール
//------------------------------
class CommonBase {
    /**
     * シングルトンインスタンス
     * @var UserManager
     */
    protected static $singleton;

    public function __construct() {
        if (self::$singleton) {
            throw new Exception('must be singleton');
        }
        self::$singleton = $this;
    }
    /**
     * シングルトンインスタンスを返す
     * @return UserManager
     */
    public static function getInstance() {
        if (!self::$singleton) {
            return new CommonBase();
        } else {
            return self::$singleton;
        }
    }
    /**
     * V2用 API送信ロジック
     * @return Result
     */
    function apiCurlAction($method, $addUrlPass, $data = null, $multiPart = null, $jsonDecode = null) {
        $header = array(
            "Authorization:Bearer ". API_KEY,
            "X-Spiral-Api-Version: 1.1",
        );
        if($multiPart) {
            $header = array_merge($header, array($multiPart));
        } else {
            $header = array_merge($header, array("Content-Type:application/json"));
        }
        if(APP_ROLE){
			$header = array_merge($header, array("X-Spiral-App-Role: ".APP_ROLE));
		}
        // curl
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_URL, API_URL. $addUrlPass);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        if ($method == "POST") {
            if ($multiPart) {
                curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            } else {
                curl_setopt($curl, CURLOPT_POSTFIELDS , json_encode($data));
            }
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        }
        if ($method == "PATCH") {
            curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        }
        if ($method == "DELETE") {
            curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        }
        $response = curl_exec($curl);
        if (curl_errno($curl)) echo curl_error($curl);
        curl_close($curl);
        if($jsonDecode){
			return $response;
		}else{
            return json_decode($response, true);
		}
    }
}
?> 
                

登録フォームブロックを設置しているページのPHPタブに貼り付けてください。
//正答ラベル値
の欄には正答であるラベル値を書き換えてください。
// 正解の配列とそれぞれの点数
には、正答であるID値とそれぞれの設問の持ち点を記載してください。
サンプルでは20点ずつ割り振られています。

解説

$SPIRAL->setTHValues($correct_answers);
に正答を表示するようのラベル値をもたせて
cp.result.value['question1']
等に渡しています。
ラベル値がイコールであれば
correct
クラスを、イコールでなければ
incorrect
付与することで色の出し分けを行っています。
その後は
$totalScore
に点数計算を行うようにして、
${cp.result.value['result']}
で出力。
$resultRecordUpdate = $commonBase->apiCurlAction("PATCH", "/apps/". APP_ID. "/dbs/". DB_ID. "/records/". $record['item']['_id'], $UpdateData);
にて更新でDBへ点数の登録を行っています。

補足

認証エリア内等で回答者に対して一度限りの回答とする場合は、
トリガで認証エリアを生成しているマスタDBへトリガで回答済みフラグ等を立て
登録ブロックをフラグによって表示、非表示を行う形にして複数回の回答を防止する処理が必要になります。

解決しない場合はこちら コンテンツに関しての
要望はこちら