Как организовать этот контекст, чтобы правильно собрать ответы каждого участника?

У меня есть форма для регистрации пользователя на конференции. Но когда пользователь нажимает "Регистрация магазина", он показывает неопределенную ошибку смещения, и проблема должна быть связана с тем, что я не правильно организовываю этот контекст. Форма для регистрации на конференции отличается в зависимости от того, является ли столбец "all_participants" таблицы конференций "1" или "0".

Если все_частники составляют 1 в таблице конференций

Если в таблице конференций есть столбец "all_participants" со значением "1", это означает, что необходимо собрать имя и фамилию каждого участника (о каждом выбранном типе регистрации). Таким образом, форма отобразит поля формы, чтобы получить имя и фамилию каждого участника. Также, если некоторые из выбранных типов (-ов) регистрации имеют собственные связанные вопросы, необходимо собрать ответы на эти вопросы для каждого участника, если "all_participants" равно 1. На изображении выше тип регистрации "Общие" имеет собственный вопрос, Телефон ", поэтому необходимо собрать ответы двух участников, зарегистрированных с типом регистрации" Общее ".

Изображение, которое показывает форму all_participants как "1" в таблице конференций

enter image description here

После того, как пользователь нажал кнопку "Регистрация магазина", он должен храниться в таблицах, как показано ниже:

enter image description here

Если all_participants равно 0 в таблице конференций

Если "all_participants" равно "0", у формы будет только одно поле "Телефон", потому что имя и фамилия получаются непосредственно из аутентифицированной информации пользователя. И поскольку "all_participants" равно "0", необходимо также собирать телефон пользователя, который выполняет регистрацию (аутентифицированный пользователь), для других участников нет необходимости, потому что "all_participants" - "0". Таким образом, форма, если "all_participants" равна "0", будет иметь только одно поле (Телефон) в этом случае. И таблица участников необходима только для хранения имени и фамилии пользователя, выполнившего регистрацию, так как остальные участники могут быть пусты пустыми ".

Форма, если all_participants "0":

enter image description here

После того, как пользователь нажал кнопку "Регистрация магазина", он должен храниться в таблицах, как показано ниже:

enter image description here

HTML этого контекста изображения для случая "all_participants" равен 1:

<form method="post" id="registration_form" action="http://proj.test/conference/1/conference-title/registration/storeRegistration">

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

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

  <div class="form-group">
    <label for="participant_question">Phone?</label>
    <input type="text" name="participant_question[]" class="form-control" required="">
    <input type="hidden" name="participant_question_required[]" value="1">
    <input type="hidden" value="1" name="participant_question_id[]">
  </div>

  <input type="hidden" name="rtypes[]" value="1">

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

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

  <div class="form-group">
    <label for="surnamegeneral_2">Surname</label>
    <input type="text" id="surnamegeneral_2" required="" class="form-control" name="participant_surname[]" value="">
  </div>

  <div class="form-group">
    <label for="participant_question">Phone?</label>
    <input type="text" name="participant_question[]" class="form-control" required="">
    <input type="hidden" name="participant_question_required[]" value="1">
    <input type="hidden" value="1" name="participant_question_id[]">
  </div>

  <input type="hidden" name="rtypes[]" value="1">

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

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

  <div class="form-group font-size-sm">
    <label for="surnameplus_1">Surname</label>
    <input type="text" id="surnameplus_1" required="" class="form-control" name="participant_surname[]" value="">
  </div>

  <input type="hidden" name="rtypes[]" value="2">

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

Когда пользователь нажимает "Регистрация магазина", код переходит в службу StoreRegistration() для хранения всей информации о регистрации в базе данных:

public function storeRegistration(Request $request, $id, $slug = null)
  {
      $allParticipants = Conference::where('id', $id)->first()->all_participants;
      $user = Auth::user();

      $rules = [];
      $messages = [];

      if ($allParticipants == 1) {

          $rules["participant_name.*"] = 'required|max:255|string';
          $rules["participant_surname.*"] = 'required|max:255|string';
      }

      $validator = Validator::make($request->all(), $rules);

      if ($validator->passes()) {

          $total = Session::get('total');

          $registration = Registration::create([
              'conferenec_id' => $id,
              'main_participant_id' => $user->id,
              'status' => ($total > 0) ? 'I' : 'C',
          ]);

          $participants = [];

          for ($i = 0; $i < count($request->participant_name); $i++) {
              $name = ($allParticipants) ? $request->participant_name[$i] : '';
              $surname = ($allParticipants) ? $request->participant_surname[$i] : '';
              $participants[] = Participant::create([
                  'name' => $name,
                  'surname' => $surname,
                  'registration_id' => $registration->id,
                  'registration_type_id' => $request->rtypes[$i]

              ]);
          }

          if (isset($request->participant_question)) {
              foreach( $request->participant_question as $key => $question ) {
                  $answer = Answer::create([
                      'question_id' => $request->participant_question_id[$key],
                      'participant_id' => $participants[$key]->id, // undefined index error is here
                      'answer' => $request->participant_question[$key],
                  ]);
              }
          }
          return redirect(route('user.index', ['user' => Auth::id()]).'#myTickets');
      }
      else{
          dd($validator->errors());
      }
  }

У меня есть модель вопроса, которая имеет getHtmlInput() для генерации HTML для пользовательских вопросов и добавления обязательного атрибута в поле, если "обязательный" столбец в сводной таблице "registration_type_questions" равен "1":

class Question extends Model
{
    protected $fillable = [
        'question', 'type', 'conference_id',
    ];
    public static $typeHasOptions = [
        'radio_btn',
        'select_menu',
        'checkbox'
    ];
    public function registration_type()
    {
        return $this->belongsToMany('App\RegistrationType', 'registration_type_questions')
            ->withPivot('required');
    }
    public function options()
    {
        return $this->hasMany('App\QuestionOption');
    }
    public function hasOptions()
    {
        return in_array($this->type, self::$typeHasOptions);
    }
    public function getHtmlInput($name = "", $options = "", $required = false, $customtype = false)
    {
        $html = '';
        $html .= $customtype == 'checkbox' ? "<div class='checkbox-group ".($required ? " required" : "")."'>" : '';
        $html .= $customtype == 'select_menu' ? "<select name='participant_question[]' class='form-control' " . ($required ? " required" : "")
            . ">" : '';

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

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

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

                case "long_text":
                    $html .= "
            <textarea name='participant_question' 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='participant_question[]' 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='participant_question[]' 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;
    }
}

Затем в представлении getHtmlInput() используется как:

@foreach($selectedRtype['questions'] as $customQuestion)
  <div class="form-group">
      <label for="participant_question">{{$customQuestion->question}}</label>
      @if($customQuestion->hasOptions() && in_array($customQuestion->type, ['checkbox', 'radio_btn', 'select_menu']))
          {!! $customQuestion->getHtmlInput(
              $customQuestion->name,
              $customQuestion->options,
              ($customQuestion->pivot->required == '1'),
              $customQuestion->type)
          !!}

      @else
          {!! $customQuestion->getHtmlInput(
              $customQuestion->name,
              [],
              ($customQuestion->pivot->required == '1'),
              $customQuestion->type)
          !!}
      @endif
      <input type="hidden"
             name="participant_question_required[]"
             value="{{ $customQuestion->pivot->required }}">
      <input type="hidden"
             value="{{ $customQuestion->id }}"
             name="participant_question_id[]"/>
  </div>
@endforeach

Ответ 1

Я немного изменил структуру файлов HTML.

<form method="post" id="registration_form" action="http://proj.test/conference/1/conference-title/registration/storeRegistration">

{{csrf_field()}}

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

<div class="form-group">
    <label for="surnamegeneral_1">Surname</label>
    <input type="text" id="surnamegeneral_1" required="" class="form-control" name="participant[1][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">
    <label for="namegeneral_2">Name</label>
    <input type="text" id="namegeneral_2" name="participant[2][name]" required="" class="form-control" value="">
</div>

<div class="form-group">
    <label for="surnamegeneral_2">Surname</label>
    <input type="text" id="surnamegeneral_2" required="" class="form-control" name="participant[2][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">

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

<div class="form-group font-size-sm">
    <label for="nameplus_1">Name</label>
    <input type="text" id="nameplus_1" name="participant[3][name]" required="" class="form-control" value="">
</div>

<div class="form-group font-size-sm">
    <label for="surnameplus_1">Surname</label>
    <input type="text" id="surnameplus_1" required="" class="form-control" name="participant[3][surname]" value="">
</div>

<input type="hidden" name="participant[3][rtypes]" value="2">

<input type="submit" class="btn btn-primary" value="Store Registration">

Я буду хранить все participants в массиве с именем participant и отправить ТНМЕ на Backend

выход:

array:2 [▼
  "_token" => "WDtDV0CL6OKVCsGSi5HNyi4HQ6Pmo6VAwzDsgYK1"
  "participant" => array:3 [▼
    1 => array:5 [▼
      "name" => "ali"
      "surname" => "shahabi"
      "answer" => "0937"
      "question_id" => "1"
      "rtypes" => "1"
    ]
    2 => array:5 [▼
      "name" => "danyal"
      "surname" => "shahabi"
      "answer" => "0938"
      "question_id" => "1"
      "rtypes" => "1"
    ]
    3 => array:3 [▼
      "name" => "baba"
      "surname" => "babaei"
      "rtypes" => "2"
    ]
  ]
]

storeRegistration способ.

Я удалил validation из кода и сосредоточился на логике программы:

public function storeRegistration(Request $request, $id, $slug = null)
{

    # all_participants field
    $allParticipants = Conference::where('id', $id)->first()->all_participants;

    $total = Session::get('total');

    # user object
    $user = Auth::user();

    # add registration to Database
    $registration = Registration::create([
        'conference_id' => $id,
        'main_participant_id' => $user->id,
        'status' => ($total > 0) ? 'I' : 'C',
    ]);

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

    #add all participants to Database
    foreach ($participants_list as $participant)
    {
        $name = ($allParticipants) ? $participant['name'] : '';
        $surname = ($allParticipants) ? $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'],
            ]);}
    }

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