/** * saveAnswer * save the answer data * * @param array $questionnaire questionnaire data * @param int $userId user id * @param string $sessionId session id * @param array $data Postされた回答データ * @param array &$errors error messages * @throws $ex * @return bool */ public function saveAnswer($questionnaire, $userId, $sessionId, $data, &$errors) { $errors = array(); $this->loadModels(['QuestionnaireAnswerSummary' => 'Questionnaires.QuestionnaireAnswerSummary']); //トランザクションBegin $this->setDataSource('master'); //$dataSource = $this->getDataSource(); //$dataSource->begin(); try { // 初回回答か再回答かを確認している // 初めは「ID」がPOSTに入っているかどうかで判断しようと思っていたが // Cakeは簡単にブラウザの「戻る」で前画面を表示させたりするので、 // POSTのIDは再回答であるにもかかわらず空ってことがありうる // なので毎回DBチェックするしかないかと思う I think so. // サマリレコード取得 $summary = $this->QuestionnaireAnswerSummary->forceGetAnswerSummary($questionnaire, $userId, $sessionId, array('questionnaire_origin_id' => $questionnaire['Questionnaire']['origin_id'], 'answer_status' => QuestionnairesComponent::ACTION_NOT_ACT, 'session_value' => $sessionId, 'user_id' => $userId)); $summaryId = $summary['QuestionnaireAnswerSummary']['id']; // foreach ($data as $answer) { // 質問によってバリデーション動作が変わるので $targetQuestion = Hash::extract($questionnaire['QuestionnairePage'], '{n}.QuestionnaireQuestion.{n}[origin_id=' . $answer['questionnaire_question_origin_id'] . ']'); $this->validator()->getField('answer_value')->setRule('answerValidation', array('rule' => array('checkAnswerValue', $targetQuestion[0], $answer, 'message' => ''))); // データ保存 if (QuestionnairesComponent::isMatrixInputType($targetQuestion[0]['question_type'])) { foreach ($answer as $ans) { if (!$this->__saveAnswer($ans, $summaryId, $summary)) { $errors[$ans['questionnaire_question_origin_id']] = $this->validationErrors; } } } else { if (!$this->__saveAnswer($answer, $summaryId, $summary)) { $errors[$answer['questionnaire_question_origin_id']] = $this->validationErrors; } } } //$dataSource->commit(); } catch (Exception $ex) { //$dataSource->rollback(); CakeLog::error($ex); throw $ex; } if (count($errors) == 0) { return true; } else { return false; } }
/** * __aggrigateAnswer * 集計処理の実施 * * @param array $questionnaire アンケート情報 * @param bool $contentEditable 編集可能フラグ * @param array &$questions アンケート質問(集計結果を配列追加して返します) * @return void */ private function __aggrigateAnswer($questionnaire, $contentEditable, &$questions) { // 集計データを集める際の基本条件 $baseConditions = $this->QuestionnaireAnswerSummary->getResultCondition($questionnaire); //質問毎に、まとめあげる. //$questionsは、questionnaire_question_origin_idをキーとし、questionnaire_question配下が代入されている。 // foreach ($questions as &$question) { if ($question['is_result_display'] != QuestionnairesComponent::EXPRESSION_SHOW) { //集計表示をしない、なので飛ばす continue; } // 戻り値の、この質問の合計回答数を記録しておく。 // skip ロジックがあるため、単純にsummaryのcountじゃない.. $questionConditions = $baseConditions + array('QuestionnaireAnswer.questionnaire_question_origin_id' => $question['origin_id']); $question['answer_total_cnt'] = $this->QuestionnaireAnswer->getAnswerCount($questionConditions); if (QuestionnairesComponent::isMatrixInputType($question['question_type'])) { $this->__aggrigateAnswerForMatrix($question, $questionConditions); } else { $this->__aggrigateAnswerForNotMatrix($question, $questionConditions); } } }
/** * __getMatrixAns * * @param array $question question data * @param array $choice question choice data * @param array $answers answer data * @return string */ private function __getMatrixAns($question, $choice, $answers) { $retAns = ''; // 回答配列データの中から、現在指定された質問に該当するものを取り出す // マトリクスタイプのときは複数存在する(行数分) $anss = Hash::extract($answers, '{n}[questionnaire_question_origin_id=' . $question['origin_id'] . ']'); if (empty($anss)) { return $retAns; } // その中かから現在指定された選択肢行に該当するものを取り出す $ans = Hash::extract($anss, '{n}[matrix_choice_id=' . $choice['origin_id'] . ']'); // 回答が存在するとき処理 if ($ans) { $ans = $ans[0]; // 選択肢タイプのときは、回答データに選択肢IDとか、複数選ばれていたりとかあるので加工が必要 // 回答を取り出す // choice_id と choice_valueに分けられた回答選択肢配列を得る $dividedAnsArray = QuestionnairesComponent::getChoiceValueFromAnswerForSelection($ans['answer_value']); // 回答値の先頭に行側の値を入れる。 // idから判断して、その他が選ばれていた場合、other_answer_valueを入れる if ($choice['other_choice_type'] != QuestionnairesComponent::OTHER_CHOICE_TYPE_NO_OTHER_FILED) { $retAns = $ans['other_answer_value'] . QuestionnairesComponent::ANSWER_VALUE_DELIMITER; } else { $retAns = $choice['choice_label'] . QuestionnairesComponent::ANSWER_VALUE_DELIMITER; } // 選択されていた数分処理 foreach ($dividedAnsArray as $dividedAns) { if (isset($dividedAns[1])) { $retAns .= $dividedAns[1]; } else { $retAns .= ''; } $retAns .= QuestionnairesComponent::ANSWER_DELIMITER; } $retAns = trim($retAns, QuestionnairesComponent::ANSWER_DELIMITER); } return $retAns; }