diff --git a/database/migrations/create_surveyhero_tables.php.stub b/database/migrations/create_surveyhero_tables.php.stub index 6afb4a9..ca2cc08 100644 --- a/database/migrations/create_surveyhero_tables.php.stub +++ b/database/migrations/create_surveyhero_tables.php.stub @@ -53,7 +53,7 @@ class CreateSurveyheroTables extends Migration $table->bigInteger('surveyhero_answer_id')->nullable(); $table->string('converted_string_value')->nullable(); $table->integer('converted_int_value')->nullable(); - $table->json('label'); + $table->json('label')->nullable(); $table->timestamps(); }); diff --git a/src/Commands/SurveyheroMapperCommand.php b/src/Commands/SurveyheroMapperCommand.php index ef31157..cac7885 100644 --- a/src/Commands/SurveyheroMapperCommand.php +++ b/src/Commands/SurveyheroMapperCommand.php @@ -46,16 +46,18 @@ public function handle(): int $this->comment("Mapping for survey '$survey->name' completed!"); } - $myfile = fopen('mapping.txt', 'w') or exit('Unable to open file!'); - fwrite($myfile, $this->var_export_short($mapping, true)); + $fileName = 'surveyhero_mapping.php'; + $myfile = fopen($fileName, 'w') or exit('Unable to open file!'); + + fwrite($myfile, "var_export_short($mapping) . "; \n"); fclose($myfile); - $this->comment('Mapping complete! [mapping.txt]'); + $this->comment("Mapping complete! [$fileName]"); return self::SUCCESS; } - private function var_export_short($data, $return = true) + private function var_export_short($data): string { $dump = var_export($data, true); @@ -70,10 +72,6 @@ private function var_export_short($data, $return = true) $dump = preg_replace('#\)$#', ']', $dump); } - if ($return === true) { - return $dump; - } else { - echo $dump; - } + return $dump; } } diff --git a/src/Exceptions/QuestionMapperNotImplementedException.php b/src/Exceptions/QuestionMapperNotImplementedException.php new file mode 100644 index 0000000..e79055d --- /dev/null +++ b/src/Exceptions/QuestionMapperNotImplementedException.php @@ -0,0 +1,15 @@ +questionType = $questionType; + + return $ex; + } + } diff --git a/src/Exceptions/QuestionNotImportedException.php b/src/Exceptions/QuestionNotImportedException.php index 3e874a4..8eda7f5 100644 --- a/src/Exceptions/QuestionNotImportedException.php +++ b/src/Exceptions/QuestionNotImportedException.php @@ -4,12 +4,12 @@ class QuestionNotImportedException extends \Exception { - public int $answerId; + public int $questionId; - public static function create(int $answerId, string $message): self + public static function create(int $questionId, string $message): self { $ex = new self($message); - $ex->answerId = $answerId; + $ex->questionId = $questionId; return $ex; } diff --git a/src/Models/SurveyAnswer.php b/src/Models/SurveyAnswer.php index c465cb2..d28dd2a 100644 --- a/src/Models/SurveyAnswer.php +++ b/src/Models/SurveyAnswer.php @@ -20,6 +20,9 @@ class SurveyAnswer extends Model use HasFactory; use HasTranslations; + const CONVERTED_TYPE_INT = 'int'; + const CONVERTED_TYPE_STRING = 'string'; + protected $translatable = ['label']; protected $guarded = []; diff --git a/src/Services/Factories/QuestionAndAnswerCreator/AbstractQuestionAndAnswerCreator.php b/src/Services/Factories/QuestionAndAnswerCreator/AbstractQuestionAndAnswerCreator.php index 641a6f9..f6ff36c 100644 --- a/src/Services/Factories/QuestionAndAnswerCreator/AbstractQuestionAndAnswerCreator.php +++ b/src/Services/Factories/QuestionAndAnswerCreator/AbstractQuestionAndAnswerCreator.php @@ -4,6 +4,7 @@ use Statikbe\Surveyhero\Exceptions\AnswerNotMappedException; use Statikbe\Surveyhero\Models\Survey; +use Statikbe\Surveyhero\Models\SurveyAnswer; use Statikbe\Surveyhero\Models\SurveyQuestion; use Statikbe\Surveyhero\Services\SurveyMappingService; @@ -52,17 +53,17 @@ protected function setChoiceAndConvertToDataType(mixed $mappedChoice, { //if the choice is not mapped try to set the label as string: if (! $mappedChoice) { - if ($dataType === 'string') { + if ($dataType === SurveyAnswer::CONVERTED_TYPE_STRING) { $responseData['converted_string_value'] = $surveyheroChoice->label; } else { throw AnswerNotMappedException::create($surveyheroChoice->choice_id, "The choice mapping could not be made for choice ID: $surveyheroChoice->choice_id"); } } else { switch ($dataType) { - case 'int': + case SurveyAnswer::CONVERTED_TYPE_INT: $responseData['converted_int_value'] = $mappedChoice; break; - case 'string': + case SurveyAnswer::CONVERTED_TYPE_STRING: $responseData['converted_string_value'] = $mappedChoice; break; } diff --git a/src/Services/Factories/QuestionMapper/AbstractQuestionMapper.php b/src/Services/Factories/QuestionMapper/AbstractQuestionMapper.php new file mode 100644 index 0000000..f8cb111 --- /dev/null +++ b/src/Services/Factories/QuestionMapper/AbstractQuestionMapper.php @@ -0,0 +1,23 @@ + $questionId, + 'type' => $questionType, + 'field' => 'question_'.$questionFieldSuffix, + 'mapped_data_type' => $mappedDataType, + ]; + } + } diff --git a/src/Services/Factories/QuestionMapper/ChoiceListQuestionMapper.php b/src/Services/Factories/QuestionMapper/ChoiceListQuestionMapper.php new file mode 100644 index 0000000..9d67775 --- /dev/null +++ b/src/Services/Factories/QuestionMapper/ChoiceListQuestionMapper.php @@ -0,0 +1,22 @@ +createQuestionMap($question->element_id, + $question->question->type, + SurveyAnswer::CONVERTED_TYPE_INT, + $questionCounter); + + foreach ($question->question->choice_list->choices as $choiceKey => $choice) { + $questionData['answer_mapping'][$choice->choice_id] = $choiceKey + 1; + } + return $questionData; + } + } diff --git a/src/Services/Factories/QuestionMapper/ChoiceTableQuestionMapper.php b/src/Services/Factories/QuestionMapper/ChoiceTableQuestionMapper.php new file mode 100644 index 0000000..0864ee0 --- /dev/null +++ b/src/Services/Factories/QuestionMapper/ChoiceTableQuestionMapper.php @@ -0,0 +1,34 @@ +question->choice_table->choices as $questionChoice){ + $answerMapping[$questionChoice->choice_id] = $choiceCounter; + $choiceCounter ++; + } + + //create subquestions: + foreach ($question->question->choice_table->rows as $rowQuestion){ + $questionData = $this->createQuestionMap($rowQuestion->row_id, + $question->question->type, + SurveyAnswer::CONVERTED_TYPE_INT, + "{$questionCounter}_{$subquestionIndex}"); + + $questionData['answer_mapping'] = $answerMapping; + $mappedQuestions[] = $questionData; + } + + return $mappedQuestions; + } + } diff --git a/src/Services/Factories/QuestionMapper/InputQuestionMapper.php b/src/Services/Factories/QuestionMapper/InputQuestionMapper.php new file mode 100644 index 0000000..46bdd5b --- /dev/null +++ b/src/Services/Factories/QuestionMapper/InputQuestionMapper.php @@ -0,0 +1,18 @@ +createQuestionMap($question->element_id, + $question->question->type, + SurveyAnswer::CONVERTED_TYPE_STRING, + $questionCounter); + + return $questionData; + } + } diff --git a/src/Services/Factories/QuestionMapper/QuestionMapper.php b/src/Services/Factories/QuestionMapper/QuestionMapper.php new file mode 100644 index 0000000..4be4b58 --- /dev/null +++ b/src/Services/Factories/QuestionMapper/QuestionMapper.php @@ -0,0 +1,7 @@ +createQuestionMap($question->element_id, + $question->question->type, + SurveyAnswer::CONVERTED_TYPE_STRING, + $questionCounter); + + if ($question->question->rating_scale->style == 'numerical_scale') { + $questionData['mapped_data_type'] = SurveyAnswer::CONVERTED_TYPE_INT; + } + + return $questionData; + } + } diff --git a/src/Services/Factories/ResponseCreator/AbstractQuestionResponseCreator.php b/src/Services/Factories/ResponseCreator/AbstractQuestionResponseCreator.php index 9d86613..5753335 100644 --- a/src/Services/Factories/ResponseCreator/AbstractQuestionResponseCreator.php +++ b/src/Services/Factories/ResponseCreator/AbstractQuestionResponseCreator.php @@ -2,8 +2,10 @@ namespace Statikbe\Surveyhero\Services\Factories\ResponseCreator; +use Statikbe\Surveyhero\Exceptions\AnswerNotImportedException; use Statikbe\Surveyhero\Exceptions\AnswerNotMappedException; use Statikbe\Surveyhero\Exceptions\QuestionNotImportedException; +use Statikbe\Surveyhero\Models\SurveyAnswer; use Statikbe\Surveyhero\Models\SurveyQuestion; use Statikbe\Surveyhero\Models\SurveyQuestionResponse; use Statikbe\Surveyhero\Models\SurveyResponse; @@ -34,27 +36,43 @@ protected function findExistingQuestionResponse(string|int $surveyheroQuestionId } /** - * @param \stdClass $surveyheroQuestionResponse - * @param SurveyResponse $response - * @param string $field - * @return array{ 'survey_question_id': int, 'field': string, 'survey_response_id': int } - * - * @throws \Statikbe\Surveyhero\Exceptions\QuestionNotImportedException + * @param string $surveyheroQuestionId + * @return SurveyQuestion + * @throws QuestionNotImportedException */ - protected function createSurveyQuestionResponseData(\stdClass $surveyheroQuestionResponse, - SurveyResponse $response, - string $field): array - { - $surveyQuestion = SurveyQuestion::where('surveyhero_question_id', $surveyheroQuestionResponse->element_id)->first(); + protected function findSurveyQuestion(string $surveyheroQuestionId): SurveyQuestion { + $surveyQuestion = SurveyQuestion::where('surveyhero_question_id', $surveyheroQuestionId)->first(); + if(!$surveyQuestion){ + throw QuestionNotImportedException::create($surveyheroQuestionId, 'The question is not imported'); + } + else return $surveyQuestion; + } - if (! $surveyQuestion) { - throw QuestionNotImportedException::create($surveyheroQuestionResponse->element_id, "Make sure to import survey question with Surveyhero ID $surveyheroQuestionResponse->element_id in the survey_questions table"); + protected function findSurveyAnswer(SurveyQuestion $question, string $surveyheroAnswerId): SurveyAnswer { + $surveyAnswer = SurveyAnswer::where('survey_question_id', $question->id) + ->where('surveyhero_answer_id', $surveyheroAnswerId) + ->first(); + + if (! $surveyAnswer) { + throw AnswerNotImportedException::create($surveyheroAnswerId, "Make sure to import survey answer with Surveyhero ID $surveyheroAnswerId in the survey_answers table"); } + else return $surveyAnswer; + } + /** + * @param SurveyQuestion $question + * @param SurveyResponse $response + * @param SurveyAnswer|null $answer + * @return array{ 'survey_question_id': int, 'survey_response_id': int } + */ + protected function createSurveyQuestionResponseData(SurveyQuestion $question, + SurveyResponse $response, + ?SurveyAnswer $answer): array + { return [ - 'survey_question_id' => $surveyQuestion->id, - 'field' => $field, + 'survey_question_id' => $question->id, 'survey_response_id' => $response->id, + 'survey_answer_id' => $answer ? $answer->id : null, ]; } @@ -71,31 +89,67 @@ protected function getChoiceMapping(string|int $choiceId, array $questionMapping * @param mixed $mappedChoice * @param string $dataType * @param array $responseData - * @param \stdClass $surveyheroChoice + * @param \stdClass|null $surveyheroChoice * * @throws AnswerNotMappedException */ protected function setChoiceAndConvertToDataType(mixed $mappedChoice, string $dataType, array &$responseData, - \stdClass $surveyheroChoice): void + ?\stdClass $surveyheroChoice): void { //if the choice is not mapped try to set the label as string: - if (! $mappedChoice) { - if ($dataType === 'string') { + if (! $mappedChoice && $surveyheroChoice) { + if ($dataType === SurveyAnswer::CONVERTED_TYPE_STRING) { $responseData['converted_string_value'] = $surveyheroChoice->label; } else { throw AnswerNotMappedException::create($surveyheroChoice->choice_id, "The choice mapping could not be made for choice ID: $surveyheroChoice->choice_id"); } } else { switch ($dataType) { - case 'int': + case SurveyAnswer::CONVERTED_TYPE_INT: $responseData['converted_int_value'] = $mappedChoice; break; - case 'string': + case SurveyAnswer::CONVERTED_TYPE_STRING: $responseData['converted_string_value'] = $mappedChoice; break; } } } + + protected function fetchOrCreateInputAnswer(SurveyQuestion $surveyQuestion, string $answerDataType, mixed $inputAnswer): SurveyAnswer { + //fetch or create answer: + $answerData = []; + $this->setChoiceAndConvertToDataType($this->transformInputToDataType($inputAnswer, $answerDataType), + $answerDataType, + $answerData, + null); + $surveyAnswerQuery = SurveyAnswer::where('survey_question_id', $surveyQuestion->id); + if(isset($answerData['converted_int_value'])){ + $surveyAnswerQuery->where('converted_int_value', $answerData['converted_int_value']); + } + else if(isset($answerData['converted_string_value'])){ + $surveyAnswerQuery->where('converted_string_value', $answerData['converted_string_value']); + } + $surveyAnswer = $surveyAnswerQuery->first(); + + if (! $surveyAnswer) { + $answerData['survey_question_id'] = $surveyQuestion->id; + $answerData['surveyhero_answer_id'] = null; + $surveyAnswer = SurveyAnswer::create($answerData); + } + + return $surveyAnswer; + } + + protected function transformInputToDataType(mixed $input, string $dataType){ + switch($dataType){ + case SurveyAnswer::CONVERTED_TYPE_INT: + return intval($input); + case SurveyAnswer::CONVERTED_TYPE_STRING: + return strval($input); + default: + return $input; + } + } } diff --git a/src/Services/Factories/ResponseCreator/ChoiceTableResponseCreator.php b/src/Services/Factories/ResponseCreator/ChoiceTableResponseCreator.php index da26343..8c9dc9f 100644 --- a/src/Services/Factories/ResponseCreator/ChoiceTableResponseCreator.php +++ b/src/Services/Factories/ResponseCreator/ChoiceTableResponseCreator.php @@ -85,16 +85,10 @@ public function updateOrCreateQuestionResponse(\stdClass $surveyheroQuestionResp $subquestionMapping = $this->getSubquestionMapping($surveyheroChoiceQuestion->row_id, $questionMapping); foreach ($surveyheroChoiceQuestion->choices as $surveyheroChoice) { $existingQuestionResponse = $this->findExistingQuestionResponse($subquestionMapping['question_id'], $response, $surveyheroChoice->choice_id); - $responseData = $this->createSurveyQuestionResponseData($surveyheroQuestionResponse, $response, $subquestionMapping['field']); - $mappedChoice = $this->getChoiceMapping($surveyheroChoice->choice_id, $questionMapping); - $surveyAnswer = SurveyAnswer::where('surveyhero_answer_id', $surveyheroChoice->choice_id)->first(); + $surveyQuestion = $this->findSurveyQuestion($surveyheroChoiceQuestion->row_id); + $surveyAnswer = $this->findSurveyAnswer($surveyQuestion, $surveyheroChoice->choice_id); - if (! $surveyAnswer) { - throw AnswerNotImportedException::create($surveyheroChoice->choice_id, "Make sure to import survey answer with Surveyhero ID $surveyheroQuestionResponse->element_id in the survey_answers table"); - } - $responseData['survey_answer_id'] = $surveyAnswer->id; - - //$this->setChoiceAndConvertToDataType($mappedChoice, $questionMapping['mapped_data_type'], $responseData, $surveyheroChoice); + $responseData = $this->createSurveyQuestionResponseData($surveyQuestion, $response, $surveyAnswer); $responseList[] = SurveyQuestionResponse::updateOrCreate([ 'id' => $existingQuestionResponse->id ?? null, diff --git a/src/Services/Factories/ResponseCreator/ChoicesResponseCreator.php b/src/Services/Factories/ResponseCreator/ChoicesResponseCreator.php index cf1e753..0bda130 100644 --- a/src/Services/Factories/ResponseCreator/ChoicesResponseCreator.php +++ b/src/Services/Factories/ResponseCreator/ChoicesResponseCreator.php @@ -3,7 +3,9 @@ namespace Statikbe\Surveyhero\Services\Factories\ResponseCreator; use Statikbe\Surveyhero\Exceptions\AnswerNotImportedException; +use Statikbe\Surveyhero\Exceptions\QuestionNotImportedException; use Statikbe\Surveyhero\Models\SurveyAnswer; +use Statikbe\Surveyhero\Models\SurveyQuestion; use Statikbe\Surveyhero\Models\SurveyQuestionResponse; use Statikbe\Surveyhero\Models\SurveyResponse; @@ -52,21 +54,14 @@ public function updateOrCreateQuestionResponse( //TODO remove deselected answers foreach ($surveyheroQuestionResponse->choices as $surveyheroChoice) { $existingQuestionResponse = $this->findExistingQuestionResponse($questionMapping['question_id'], $response, $surveyheroChoice->choice_id); - $responseData = $this->createSurveyQuestionResponseData($surveyheroQuestionResponse, $response, $questionMapping['field']); - $mappedChoice = $this->getChoiceMapping($surveyheroChoice->choice_id, $questionMapping); - $surveyAnswer = SurveyAnswer::where('surveyhero_answer_id', $surveyheroChoice->choice_id)->first(); + $surveyQuestion = $this->findSurveyQuestion($surveyheroQuestionResponse->element_id); + $surveyAnswer = $this->findSurveyAnswer($surveyQuestion, $surveyheroChoice->choice_id); - if (! $surveyAnswer) { - throw AnswerNotImportedException::create($surveyheroChoice->choice_id, "Make sure to import survey answer with Surveyhero ID $surveyheroQuestionResponse->element_id in the survey_answers table"); - } - $responseData['survey_answer_id'] = $surveyAnswer->id; - - //$this->setChoiceAndConvertToDataType($mappedChoice, $questionMapping['mapped_data_type'], $responseData, $surveyheroChoice); - //$responseData['surveyhero_answer_lbl'] = $surveyheroChoice->label; + $responseData = $this->createSurveyQuestionResponseData($surveyQuestion, $response, $surveyAnswer); $responseList[] = SurveyQuestionResponse::updateOrCreate([ - 'id' => $existingQuestionResponse->id ?? null, - ], $responseData); + 'id' => $existingQuestionResponse->id ?? null, + ], $responseData); } return $responseList; diff --git a/src/Services/Factories/ResponseCreator/NumberResponseCreator.php b/src/Services/Factories/ResponseCreator/NumberResponseCreator.php index 2f25492..0f642f8 100644 --- a/src/Services/Factories/ResponseCreator/NumberResponseCreator.php +++ b/src/Services/Factories/ResponseCreator/NumberResponseCreator.php @@ -21,22 +21,23 @@ public function updateOrCreateQuestionResponse(\stdClass $surveyheroQuestionResp * 'type' => 'number', * 'field' => 'age', * ], + * + * Surveyhero API response: + * { + * "element_id": 6059049, + * "question_text": "Your age", + * "type": "number", + * "number": 5 + * } */ $existingQuestionResponse = $this->findExistingQuestionResponse($questionMapping['question_id'], $response); + $surveyQuestion = $this->findSurveyQuestion($surveyheroQuestionResponse->element_id); + $surveyAnswer = $this->fetchOrCreateInputAnswer($surveyQuestion, + $questionMapping['mapped_data_type'] ?? SurveyAnswer::CONVERTED_TYPE_INT, + $surveyheroQuestionResponse->number); - $responseData = $this->createSurveyQuestionResponseData($surveyheroQuestionResponse, $response, $questionMapping['field']); - //if later other numeric types are needed, this should decide in which column to store and format the value accordingly: - //$responseData['converted_int_value'] = intval($surveyheroQuestionResponse->number); - - $surveyAnswer = SurveyAnswer::where('converted_int_value', intval($surveyheroQuestionResponse->number)) - ->where('survey_question_id', $responseData['survey_question_id']) - ->first(); - - if (! $surveyAnswer) { - throw AnswerNotImportedException::create(intval($surveyheroQuestionResponse->number), "Make sure to import survey answer with Surveyhero ID $surveyheroQuestionResponse->element_id in the survey_answers table"); - } - $responseData['survey_answer_id'] = $surveyAnswer->id; + $responseData = $this->createSurveyQuestionResponseData($surveyQuestion, $response, $surveyAnswer); return SurveyQuestionResponse::updateOrCreate([ 'id' => $existingQuestionResponse->id ?? null, diff --git a/src/Services/Factories/ResponseCreator/TextResponseCreator.php b/src/Services/Factories/ResponseCreator/TextResponseCreator.php index c7f762b..6d4df05 100644 --- a/src/Services/Factories/ResponseCreator/TextResponseCreator.php +++ b/src/Services/Factories/ResponseCreator/TextResponseCreator.php @@ -24,18 +24,12 @@ public function updateOrCreateQuestionResponse(\stdClass $surveyheroQuestionResp */ $existingQuestionResponse = $this->findExistingQuestionResponse($questionMapping['question_id'], $response); + $surveyQuestion = $this->findSurveyQuestion($surveyheroQuestionResponse->element_id); + $surveyAnswer = $this->fetchOrCreateInputAnswer($surveyQuestion, + $questionMapping['mapped_data_type'] ?? SurveyAnswer::CONVERTED_TYPE_STRING, + $surveyheroQuestionResponse->text); - $responseData = $this->createSurveyQuestionResponseData($surveyheroQuestionResponse, $response, $questionMapping['field']); - //$responseData['converted_string_value'] = $surveyheroQuestionResponse->text; - - $surveyAnswer = SurveyAnswer::where('converted_string_value', $surveyheroQuestionResponse->text) - ->where('survey_question_id', $responseData['survey_question_id']) - ->first(); - - if (! $surveyAnswer) { - throw AnswerNotImportedException::create(intval($surveyheroQuestionResponse->text), "Make sure to import survey answer with Surveyhero ID $surveyheroQuestionResponse->element_id in the survey_answers table"); - } - $responseData['survey_answer_id'] = $surveyAnswer->id; + $responseData = $this->createSurveyQuestionResponseData($surveyQuestion, $response, $surveyAnswer); return SurveyQuestionResponse::updateOrCreate([ 'id' => $existingQuestionResponse->id ?? null, diff --git a/src/Services/SurveyMappingService.php b/src/Services/SurveyMappingService.php index a44d515..eedb9a5 100644 --- a/src/Services/SurveyMappingService.php +++ b/src/Services/SurveyMappingService.php @@ -2,10 +2,25 @@ namespace Statikbe\Surveyhero\Services; +use Statikbe\Surveyhero\Exceptions\QuestionMapperNotImplementedException; use Statikbe\Surveyhero\Exceptions\QuestionNotMappedException; use Statikbe\Surveyhero\Exceptions\SurveyNotMappedException; use Statikbe\Surveyhero\Http\SurveyheroClient; use Statikbe\Surveyhero\Models\Survey; +use Statikbe\Surveyhero\Models\SurveyAnswer; +use Statikbe\Surveyhero\Services\Factories\QuestionAndAnswerCreator\ChoiceListQuestionAndAnswerCreator; +use Statikbe\Surveyhero\Services\Factories\QuestionAndAnswerCreator\ChoiceTableQuestionAndAnswerCreator; +use Statikbe\Surveyhero\Services\Factories\QuestionAndAnswerCreator\RatingScaleQuestionAndAnswerCreator; +use Statikbe\Surveyhero\Services\Factories\QuestionMapper\ChoiceListQuestionMapper; +use Statikbe\Surveyhero\Services\Factories\QuestionMapper\ChoiceTableQuestionMapper; +use Statikbe\Surveyhero\Services\Factories\QuestionMapper\InputQuestionMapper; +use Statikbe\Surveyhero\Services\Factories\QuestionMapper\QuestionMapper; +use Statikbe\Surveyhero\Services\Factories\QuestionMapper\RatingScaleQuestionMapper; +use Statikbe\Surveyhero\Services\Factories\ResponseCreator\ChoicesResponseCreator; +use Statikbe\Surveyhero\Services\Factories\ResponseCreator\ChoiceTableResponseCreator; +use Statikbe\Surveyhero\Services\Factories\ResponseCreator\NumberResponseCreator; +use Statikbe\Surveyhero\Services\Factories\ResponseCreator\QuestionResponseCreator; +use Statikbe\Surveyhero\Services\Factories\ResponseCreator\TextResponseCreator; class SurveyMappingService { @@ -33,24 +48,31 @@ public function __construct() public function map(Survey $survey): array { $questions = $this->client->getSurveyQuestions($survey->surveyhero_id); - $mapping['survey_id'] = (int) $survey->surveyhero_id; - foreach ($questions as $index => $question) { - $mapping['questions'][$index]['question_id'] = $question->element_id; - $mapping['questions'][$index]['type'] = $question->question->type; - $mapping['questions'][$index]['field'] = 'READABLE_NAME'; - $mapping['questions'][$index]['mapped_data_type'] = null; + $mapping = [ + 'survey_id' => (int) $survey->surveyhero_id, + 'questions' => [], + ]; + $questionCounter = 1; + foreach ($questions as $question) { + $mapper = $this->getQuestionMapper($question->question->type); - if ($question->question->type == 'choice_list') { - foreach ($question->question->choice_list->choices as $choiceKey => $choice) { - $mapping['questions'][$index]['answer_mapping'][$choice->choice_id] = $choiceKey + 1; + if($mapper) { + //a mapper can return one question or multiple. + $mappedQuestions = $mapper->mapQuestion($question, $questionCounter); + if(!empty($mappedQuestions)){ + if(is_array(array_values($mappedQuestions)[0])){ + //multiple questions mapped: + $mapping['questions'] = array_merge($mapping['questions'], $mappedQuestions); + } } - $mapping['questions'][$index]['mapped_data_type'] = 'int'; - } - - if ($question->question->type == 'rating_scale') { - if ($question->question->rating_scale->style == 'numerical_scale') { - $mapping['questions'][$index]['mapped_data_type'] = 'int'; + else { + //only one question mapped: + $mapping['questions'][] = $mappedQuestions; } + $questionCounter++; + } + else { + throw QuestionMapperNotImplementedException::create($question->question->type); } } @@ -152,4 +174,15 @@ public function findQuestionField(Survey $survey, string $questionId, ?string $s //in case nothing is found there is no mapping for the question -> throw error throw QuestionNotMappedException::create($subquestionId ?? $questionId, 'The question mapping has no field'); } + + private function getQuestionMapper(string $surveyheroFieldType): ?QuestionMapper + { + return match ($surveyheroFieldType) { + InputQuestionMapper::TYPE => new InputQuestionMapper(), + RatingScaleQuestionMapper::TYPE => new RatingScaleQuestionMapper(), + ChoiceListQuestionMapper::TYPE => new ChoiceListQuestionMapper(), + ChoiceTableQuestionMapper::TYPE => new ChoiceTableQuestionMapper(), + default => null, + }; + } } diff --git a/src/Services/SurveyResponseImportService.php b/src/Services/SurveyResponseImportService.php index a886e95..9c4e481 100644 --- a/src/Services/SurveyResponseImportService.php +++ b/src/Services/SurveyResponseImportService.php @@ -128,15 +128,17 @@ private function createOrUpdateSurveyResponse(\stdClass $surveyheroResponse, Sur ]; //map link parameters: - $linkParametersConfig = config('surveyhero.surveyhero_link_parameters_mapping', []); - foreach ($linkParametersConfig as $surveyheroLinkParameter => $settings) { - if (isset($surveyheroResponse->link_parameters->{$surveyheroLinkParameter})) { - if (isset($settings['entity']) && isset($settings['value']) && isset($settings['field'])) { - //Map parameter to value of associated model - $responseData[$settings['name']] = optional($settings['entity']::where($settings['value'], $surveyheroResponse->link_parameters->{$surveyheroLinkParameter})->first())->id; - } else { - //map parameter directly to database column - $responseData[$settings['name']] = $surveyheroResponse->link_parameters->{$surveyheroLinkParameter}; + if(isset($surveyheroResponse->link_parameters)) { + $linkParametersConfig = config('surveyhero.surveyhero_link_parameters_mapping', []); + foreach($linkParametersConfig as $surveyheroLinkParameter => $settings) { + if(isset($surveyheroResponse->link_parameters->{$surveyheroLinkParameter})) { + if(isset($settings['entity']) && isset($settings['value']) && isset($settings['field'])) { + //Map parameter to value of associated model + $responseData[$settings['name']] = optional($settings['entity']::where($settings['value'], $surveyheroResponse->link_parameters->{$surveyheroLinkParameter})->first())->id; + } else { + //map parameter directly to database column + $responseData[$settings['name']] = $surveyheroResponse->link_parameters->{$surveyheroLinkParameter}; + } } } }