How to collect the answers to custom questions? (so that is possible to store the answers in the answers table)


#1

I have a model “Conference” and a conference can have one or more registration types. For example the conference “conference test” has two registration types associated: the registration type “general” and the registration type “plus”. The user that created the conference can craete how many registration types he wants for the conference that he has createad. And for each registration type he can create custom questions, for example “Whats your phone?”.

In the case of the conference “conference test”, the registration type “general” has 2 custom questions associated and the registration type “plus” dont have any custom question associated.

If a user is doing a registration in the conference “conference test” and selects that he wants quantity “2” for the registration type “plus” and click “Next” the user is redirected to the registration page. In this page there is the registration form that in this case it will only ask for the name and surname of both participants, so the form is like: https://ibb.co/bJFsoK

When the user clicks in “Next” the $request data is like:

    array:4 [▼
      "participant" => array:2 [▼
        1 => array:3 [▼
          "name" => "John"
          "surname" => "K"
          "rtypes" => "2"
        ]
        2 => array:3 [▼
          "name" => "Jake"
          "surname" => "W"
          "rtypes" => "2"
        ]
      ]
    ]

And the information is stored with success in the database using the storeRegistration().


Doubt:

My doubt is when the user is doing a registration and selected a registration type(s) that has custom questions associated.

For example if instaed of the above scenario, the user selects the quantity “2” for the registration type “general” and “0” for the registration type “plus” and click “Next”, the registration form besides the name and surname will also ask for the “Phone” because the user selected quantity “2” for the registration type “general” that has a custom question associated (Phone). So the registration form will be like:

reg2

My doubt is how we can store, besides the name and surname of each participant, the answers to the custom questions so that is possible to store in the answers table the answers of each participant.

Do you know how to properly achieve that?

Registration form in the case of the user select the quantity “2” for the registration type “general” and “0” for “plus”:

<form method="post"
    action="https://proj.test/conference/1/conference-test/registration/storeRegistration">

            <h6>Participant - 1 - general</h6>

            <div class="form-group font-size-sm">
                <label for="namegeneral_1"
                       class="text-gray">Name</label>
                <input type="text" required id="namegeneral_1"
                       name="participant[name]"
                       class="form-control" value="">
            </div>
            <div class="form-group font-size-sm">
                <label for="surnamegeneral_1"
                       class="text-gray">Surname</label>
                <input type="text" required id="surnamegeneral_1"
                       class="form-control"
                       name="participant[surname]" value="">
            </div>
    
            <div class="form-group">
                <label for="participant_question">Phone</label>
    
                <input type='text' name='participant[1][answer]' class='form-control' required>
                <input type="hidden"
                       name="participant_question_required[]"
                       value="1">
                <input type="hidden"
                       value="1"
                       name="participant[1][question_id]"/>
            </div>
           
            <input type="hidden" name="participant[1][rtypes]" value="1"/>

            <h6>Participant - 2 - general</h6>
          <div class="form-group font-size-sm">
                <label for="namegeneral_2"
                       class="text-gray">Name</label>
                <input type="text" required id="namegeneral_2"
                       name="participant[name]"
                       class="form-control" value="">
            </div>
            <div class="form-group font-size-sm">
                <label for="surnamegeneral_2"
                       class="text-gray">Surname</label>
                <input type="text" required id="surnamegeneral_2"
                       class="form-control"
                       name="participant[surname]" value="">
            </div>
    
            <div class="form-group">
                <label for="participant_question">Phone</label>
                <input type='text' name='participant[2][answer]' class='form-control' required>
                <input type="hidden"
                       name="participant_question_required[]"
                       value="1">
                <input type="hidden"
                       value="1"
                       name="participant[2][question_id]"/>
            </div>
        
          
            
            <input type="hidden" name="participant[2][rtypes]" value="1"/>

            <input type="submit" class="btn btn-primary" value="Register"/>
    </form>

Método storeRegistration() to store the registration info:

public function storeRegistration(Request $request, $id, $slug = null)
    {
        # user object
        $user = Auth::user();

        # add registration to Database
        $registration = Registration::create([
            'congress_id' => $id,
            'user_that_did_registration' => $user->id,
        ]);

        # List of all participants
        $participants_list = $request->get('participant');

        #add all participants to Database
        foreach ($participants_list as $participant) {

            $name = $participant['name'];
            $surname = $participant['surname'];
            $participant_result = Participant::create([
                'name' => $name,
                'surname' => $surname,
                'registration_id' => $registration->id,
                'registration_type_id' => $participant['rtypes']
            ]);

            # save answer to Database if exist
            if (isset($participant['question_id'])) {
                $answer = Answer::create([
                    'question_id' => $participant['question_id'],
                    'participant_id' => $participant_result->id,
                    'answer' => $participant['answer'],
                ]);
            }
        }

        
        Session::flash('registration_success', 'Registration concluded.');
        return redirect(route('user.index', ['user' => Auth::id()]) . '#myTickets');
    }

#2

First, you would have the questions stored in the database. Next, you associate those questions to a specific type.

When creating the form, you query to determine if there are questions associated with the type. If they are you show them; their id corresponds to the question type.

When storing it, you associate the response to the registrar; the question id; and then the answer itself.

Looks like you are doing it properly. It would just be a matter of, does the data model support it.


#3

Thanks, I already have the questions stored in db and are associated with the respective registration types using a pivot table.

The issue is only in how to collect the answers to the custom questions in the registration form. Im not understanding how to get the answers to custom questions of each participant so that is possible to store the answers in the answers table. The answers table structure: id, participant_id, question_id, answer.


#4

Not understanding what you mean on how to collect the answer.

Looking at your form code, you are numbering the participants incorrectly. You want to start at 0. You would then iterate through the responses. Also, don’t think of the extra questions as custom. Think of all the questions as custom. So, if they want the name of the attendee, that is a question. Any and all responses are treated the same, it is just a matter of if they are included for that type. Your association table will take care of the rest.


#5

For example the user selects quantity “1” for registration type “general” and “1” for registration type “plus” and click “Next” and goes to the registration form.

In the form, the user needs to introduce the name and surname for each participant.

Then relative to the custom questions, the registration type “plus” has id 4 in DB and dont have any question associated. So its ok.

The registration type “general” has id 1 in DB and it has 6 custom questions associated with it. The questions and the answers answered by the user in the registration form were:

Question                           Answer
input text question            text answer
long text question:            long answer
select menu question:     select menu 1
checkbox question:          check1
file question:                      img.png
radio question:                  rb1

With the registration form as it is, the participants array in the $request with the data above shows like below. The name, surname, rtypes is stored properly but the answers are not be stored properly in the array. My doubt is in this part, how to properly store in the array so that is possible to store in the answers table.

  "participant" => array:3 [▼
    1 => array:5 [▼
      "name" => "John"
      "surname" => "W"
      "answer" => "img.png"
      "question_id" => "6"
      "rtypes" => "1"
    ]
    " 1" => array:1 [▼
      "answer" => "select menu1"
    ]
    2 => array:3 [▼
      "name" => "Jake"
      "surname" => "K"
      "rtypes" => "4"
    ]
  ]

Because with the answers stored properly in the array then to insert the answers in the answers table is only necessary to use something like:

foreach ($participants_list as $participant) {

    $name = $participant['name'];
    $surname = $participant['surname'];


    $participant_result = Participant::create([
         'name' => $name,
         'surname' => $surname,
         'registration_id' => $registration->id,
         'registration_type_id' => $participant['rtypes']
    ]);


    Answer::create([
        'participant_id' => $participant_result->id,
        'answer' => $participant['answer'],
        'question_id' => $participant['question_id']
    ]);
}

#6

That is likely due to this scheme on the form,

<input type="text" required id="surnamegeneral_1"
                       class="form-control"
                       name="participant[surname]" value="">
<input type='text' name='participant[1][answer]' class='form-control' required>

As opposed to this

 <input type="text" required id="surnamegeneral_1"
                       class="form-control"
                       name="participant[0][surname]" value="">
<input type='text' name='participant[0][][answer]' class='form-control' required>

This way all of the values are stored in the same array, and the answers just need to be iterated thru.


#7

Thanks!! Like that and changing the input of the question_id to “<input type="hidden" value="{{ $customQuestion->id }}" name="participant[{{$counter}}][][question_id]"/>”. The pariticpant array stays like:

   "participant" => array:2 [▼
    1 => array:15 [▼
      "name" => "John"
      "surname" => "W"
      0 => array:1 [▼
        "answer" => "text answer"
      ]
      1 => array:1 [▼
        "question_id" => "1"
      ]
      2 => array:1 [▼
        "answer" => "long answer"
      ]
      3 => array:1 [▼
        "question_id" => "2"
      ]
      4 => array:1 [▼
        "answer" => "check1"
      ]
      5 => array:1 [▼
        "question_id" => "3"
      ]
      6 => array:1 [▼
        "answer" => "rb1"
      ]
      7 => array:1 [▼
        "question_id" => "4"
      ]
      8 => array:1 [▼
        "answer" => "selectmenu1"
      ]
      9 => array:1 [▼
        "question_id" => "5"
      ]
      10 => array:1 [▼
        "answer" => "img.png"
      ]
      11 => array:1 [▼
        "question_id" => "6"
      ]
      "rtypes" => "1"
    ]
    2 => array:3 [▼
      "name" => "Jake"
      "surname" => "K"
      "rtypes" => "4"
    ]
  ]

Do you know if like that is correct to use in the foreach? The structure of the array dont seems very correct to store the info in the DB. It appears “undefined index: answer" in $participant['answer']”.

foreach ($participants_list as $participant) {

    $name = $participant['name'];
    $surname = $participant['surname'];

    $participant_result = Participant::create([
         'name' => $name,
         'surname' => $surname,
         'registration_id' => $registration->id,
         'registration_type_id' => $participant['rtypes']
    ]);


    Answer::create([
        'participant_id' => $participant_result->id,
        'answer' => $participant['answer'],
        'question_id' => $participant['question_id']
    ]);
}

The $participant[0][‘answer’] shows “text answer”.
The $participant[1][‘answer’] shows “undefined index answer”.
The $participant[2][‘answer’] shows “long answer”.
The $participant[3][‘answer’] shows “undefined index answer”.

So Im not understanding how to use the foreach and store correctly each answer of each participant. Do you know how to properly achieve that?


#8

I’d start playing with names until you get the answers succinctly.

participant[0][questions][][{question_id}][answer]


#9

@Johnn, did you figure it out?


#10

The array from the form now is like this:

"name" => array:2 [▼
  1 => array:1 [▼  
    1 => "Jake"  // name of the participant being registered in the registration_type_id "1"
  ]
  4 => array:1 [▼
    1 => "John"  // name of the participant being registered in the registration_type_id "4"
  ]
]
"surname" => array:2 [▼
  1 => array:1 [▼
    1 => "K"      // surname of the participant being registered in the registration_type_id "1"
  ]
  4 => array:1 [▼
    1 => "W"   // surname of the participant being registered in the registration_type_id "4"
  ]
]
"answer" => array:1 [▼
  1 => array:1 [▼
    1 => array:2 [▼   // this array stores the answers for the participant being registered in the registration_type_id "1"
      1 => "answer1" // for question_id "1" the user that is doing the registration  answered  "answer1"
      2 => "answer2" // for question_id "2" the user that is doing the registration  answered  "answer2"
    ]
  ]
]

But then is necessary to insert in the participants table and answers table. To insert in the participants table its working correctly with code below. But with code below is not inserting correctly in the answers table:

foreach ($request->all()['name'] as $key => $nameArray) {
    foreach ($nameArray as $nameKey => $name) {
        $participant_result = Participant::create([
            'name'                 => $name,
            'surname'              => $request['surname'][$key][$nameKey],
            'registration_id' => $registration->id,
            'registration_type_id' => $key
        ]);

        # save answer to Database if exist
        $answer = Answer::create([
            'question_id' => $request['answer'][$key], // the issue is here
            'participant_id' => $participant_result->id,
            'answer' => $request['answer'][$key][$nameKey], // and here
        ]);
    }
}

Im not geting properly the values for the question_id and answer columns of the answers table.


#11

I don’t like how nested it is, but,

I’ll have to play with it a bit later to see what I can come up with.


#12

Thanks!! Like this it works fine for the example above, where the user that is doing the registration is registering 1 participant in the registration_type_id 1 and other participant in the registrationtype_id 4. Only the registraiton_type_id 1 has questions and the questions were inserted correctly in the answers table using:

foreach ($request->all()['answer'] as $k => $v) {
    foreach ($v[$k] as $questionId => $response) {
        $answer = Answer::create([
            'question_id' => $questionId,
            'participant_id' => $participant_result->id,
            'answer' => $response,
        ]);
    }
}

However, if the user is doing a registration of 2 participants in the registration_type_id 1 he will need to answer the custom questions for both participants, so the array will be like:

 "name" => array:1 [▼
    1 => array:2 [▼
      1 => "Jake"
      2 => "John"
    ]
  ]
  "surname" => array:1 [▼
    1 => array:2 [▼
      1 => "W"
      2 => "K"
    ]
  ]
  "answer" => array:1 [▼
    1 => array:2 [▼
      1 => array:2 [▼
        1 => "answer1OfParticipant1"
        2 => "answer2OfParticipant1"
      ]
      2 => array:2 [▼
        1 => "answer2OfParticipant2"
        2 => "answer2ofParticipant2"
      ]
    ]
  ]

And with this array, the above code only inserts in database the answers for the last participant being registered. But it should insert for both participants.


#13

It’s a grouping issue. How are you creating the form? Have anything that I can play with?


#14

The registration form, if the user selected quantity 1 for the registration type “general” ( that has id 1) and quantity 1 for the registration type “plus” (that has id 4), that is the example in the question, is like this:

<form method="post"
      action="https://proj.test/conference/1/conference-test/registration/storeRegistration">

  <h6> Participant - 1 - general</h6>

  <div class="form-group">
    <label for="namegeneral_1">Name</label>
    <input type="text" required  id="namegeneral_1" name="name[1][1]" class="form-control" value="">
  </div>

  <div class="form-group">
    <label for="surnamegeneral_1">Surname</label>
    <input type="text"  id="surnamegeneral_1" class="form-control" name="surname[1][1]" value="">
  </div>

  <div class="form-group">
    <label for="participant_question">Question 1</label>
    <input type='text' name='answer[1][1][1]' class='form-control' required>
    <input type="hidden" name="question_required[1][1]"  value="1">
  </div>

  <div class="form-group">
    <label for="participant_question">Question 2 </label>
    <textarea name='answer[1][1][2]' class='form-control' rows='3' required></textarea>
    <input type="hidden" name="question_required[1][2]" value="1">
  </div>

  <h6> Participant - 1 - plus</h6>

  <div class="form-group">
    <label for="nameplus_1">Name</label>
    <input type="text" required  id="nameplus_1" name="name[4][1]" class="form-control" value="">
  </div>

  <div class="form-group">
    <label for="surnameplus_1">Surname</label>
    <input type="text"  id="surnameplus_1" class="form-control" name=" surname[4][1]" value="">
  </div>

  <input type="submit" class="btn btn-primary"  value="Register"/>
</form>

#15

The registration form, if the user select quantity 2 for the registration type “general” and none for the other registration types, is like:

<form method="post"
      action="https://proj.test/conference/1/conference-test/registration/storeRegistration">


  <h6>Participant - 1 - general</h6>

  <div class="form-group">
    <label for="namegeneral_1">Name</label>
    <input type="text" required  id="namegeneral_1" name="name[1][1]" class="form-control" value="">
  </div>

  <div class="form-group">
    <label for="surnamegeneral_1">Surname</label>
    <input type="text"  id="surnamegeneral_1" class="form-control"  name="surname[1][1]" value="">
  </div>

  <div class="form-group">
    <label for="participant_question">Question 1</label>
    <input type='text' name='answer[1][1][1]' class='form-control' required>
    <input type="hidden" name="question_required[1][1]" value="1">
  </div>

  <div class="form-group">
    <label for="participant_question">Question 2</label>
    <textarea name='answer[1][1][2]' class='form-control' rows='3' required></textarea>
    <input type="hidden" name="question_required[1][2]" value="1">
  </div>


  <h6>Participant - 2 - general</h6>


  <div class="form-group">
    <label for="namegeneral_2">Name</label>
    <input type="text" required  id="namegeneral_2" name="name[1][2]" class="form-control" value="">
  </div>

  <div class="form-group font-size-sm">
    <label for="surnamegeneral_2">Surname</label>
    <input type="text"  id="surnamegeneral_2"  class="form-control" name="surname[1][2]" value="">
  </div>

  <div class="form-group">
    <label for="participant_question">Question 1</label>
    <input type='text' name='answer[1][2][1]' class='form-control' required>
    <input type="hidden" name="question_required[1][1]"  value="1">
  </div>

  <div class="form-group">
    <label for="participant_question">Question 2</label>
    <textarea name='answer[1][2][2]' class='form-control' rows='3' required></textarea>
    <input type="hidden" name="question_required[1][2]" value="1">
  </div>

  <input type="submit" class="btn btn-primary" value="Register"/>
</form>

#16

The site really screwed up the characters


#17

So, the next part is how you actually dynamically build the forms to begin with.


#18

Thanks, like that the array shows like:

"participant" => array:3 [▼
    "general" => array:1 [▼
      "name" => "W"
    ]
    1 => array:1 [▼
      "questions" => array:6 [▼
        0 => array:1 [▼
          "question_id" => array:1 [▼
            1 => array:1 [▼
              "answer" => "answer1"
            ]
          ]
        ]
        1 => array:1 [▼
          "question_id" => array:1 [▼
            2 => array:1 [▼
              "answer" => "answer2"
            ]
          ]
        ]
      ]
    ]
    "plus" => array:1 [▼
      "name" => "K"
    ]
  ]

But like that do you know how to get the registration_type_id (that is 1 for general and 4 for plus) to insert in the participants table like:

for($index=0;$index < count($request->all()['participant']); $index++) {
    $participant_result = Participant::create([
        'name' => $request->all()['participant'][$index]['name'],
        'surname' => $request->all()['participant'][$index]['surname'],
        'registration_id' => $registration->id,
        'registration_type_id' => //?
    ]);
}

And it shows “Undefined offset: 0” in " “’name' => $request->all()['participant'][$index]['name'],


#19

I have this method to create the questions html based on the question type:

public function getHtmlInput($name = "", $options = "", $required = false, $customtype = false, $k = null, $selectedRtypeId, $customQuestionId)
    {
        $html = '';
        $html .= $customtype == 'checkbox' ? "<div class='checkbox-group ".($required ? " required" : "")."'>" : '';
        $html .= $customtype == 'select_menu' ? "<select name='answer[$selectedRtypeId][$k][$customQuestionId]' class='form-control' " . ($required ? " required" : "")
            . ">" : '';

        if (empty($options)) {
            switch ($customtype) {
                case "text":

                    $html .= "           
                <input type='text' name='answer[$selectedRtypeId][$k][$customQuestionId]' class='form-control'" . ($required ? " required" : "")
                        . ">";
                    break;

                case "file":
                    $html .= " 
                <input type='file' name='answer[$selectedRtypeId][$k][$customQuestionId]' class='form-control'" . ($required ? " required" : "") . ">";
                    break;

                case "long_text":
                    $html .= "
            <textarea name='answer[$selectedRtypeId][$k][$customQuestionId]' class='form-control' rows='3'" . ($required ? " required" : "") . ">"
                        . $name .
                        "</textarea>";
                    break;
            }
        } else {
            foreach ($options as $option) {
                switch ($customtype) {
                    case "checkbox":
                        $html .= " 
        <div class='form-check'>
            <input type='checkbox' name='answer[$selectedRtypeId][$k][$customQuestionId]' value='" . $option->value . "' class='form-check-input' >
                <label class='form-check-label' for='exampleCheck1'>" . $option->value . "</label>
        </div>";
                        break;
                    case "radio_btn":
                        $html .= " 
            <div class='form-check'>
                <input type='radio' name='answer[$selectedRtypeId][$k][$customQuestionId]' value='" . $option->value . "' class='form-check-input'" . ($required ? " required" : "") . ">" .
                            '    <label class="form-check-label" for="exampleCheck1">' . $option->value . '</label>' .
                            "</div>";
                        break;
                    case "select_menu":
                        $html .= "<option value='" . $option->value . "'>" . $option->value . "</option>";
                        break;
                }
            }
        }
        $html .= $customtype == 'select_menu' ? "</select>" : '';
        $html .= $customtype == 'checkbox' ? "</div>" : '';

        return $html;
    }

And to create the form:

@foreach($selectedRtypes as $k => $selectedRtype)
    <?php $counter = 1; ?>
    @foreach(range(1,$selectedRtype['quantity']) as $val)
        <h6>Participant - {{$counter}} - {{$k}}</h6>
        
        <div class="form-group">
            <label for="name{{ $k }}_{{ $counter }}">Name</label>
            <input type="text" required  id="name{{ $k }}_{{ $counter }}" name="name[{{ $selectedRtype['id']}}][{{ $counter }}]" class="form-control" value="">
        </div>

        <div class="form-group">
            <label for="surname{{ $k }}_{{ $counter }}">Surname</label>
            <input type="text"  id="surname{{ $k }}_{{ $counter }}" class="form-control" name=" surname[{{ $selectedRtype['id']}}][{{ $counter }}]" value="">
        </div>

        @foreach($selectedRtype['questions'] as $customQuestion)
            <div class="form-group">
                <label for="participant_question">{{$customQuestion->question}}
                @if($customQuestion->hasOptions() && in_array($customQuestion->type, ['checkbox', 'radio_btn', 'select_menu']))
                    {!! $customQuestion->getHtmlInput(
		            $customQuestion->name,
		            $customQuestion->options,
		            ($customQuestion->pivot->required == '1'),
		            $customQuestion->type,
		            $counter,
		            $selectedRtype['id'],
		           $customQuestion->id)
		        !!}
                @else
                    {!! $customQuestion->getHtmlInput(
                    $customQuestion->name,
                    [],
                    ($customQuestion->pivot->required == '1'),
                    $customQuestion->type,
                    $counter,
                    $selectedRtype['id'],
                    $customQuestion->id
                    )
                    !!}
                @endif
                <input type="hidden" name="question_required[{{ $selectedRtype['id'] }}][{{ $customQuestion->id }}]"
                       value="{{ $customQuestion->pivot->required }}">
            </div>
        @endforeach
        <?php $counter++; ?>
    @endforeach
@endforeach

<input type="submit" class="btn btn-primary" value="Register"/>

The “$selectedRtypes” in “@foreach($selectedRtypes as $k => $selectedRtype)” store the quantities of each registration type selected by the user that is doing the registration for example if the user select quantiy 1 for general and 1 for plus it shows:

array:2 [▼
  "general" => array:3[▼
    "quantity" => "1"
    "questions" => Collection {#287 ▶}
    "id" => 1
  ]
  "plus" => array:3 [▼
    "quantity" => "1"
    "questions" => Collection {#301 ▼
      #items: []
    }
    "id" => 4
  ]
]

#20

I don’t know what $request->all() holds, I would say you are trying to access the values incorrectly.