Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store registration is not working properly (the code goes always to the else part of the "if ($validator->passes()) {...}"

Tags:

php

laravel

I have a form in the registration.blade.php page for a user to enter some info to do a registration in a conference.

In the form below there is a part where is used the getHtmlInput() method, that is used to show for each ticket/registration type selected by the user the custom question(s) associated with that registration type for the user to answer. And adds the "required" attribute if in the registration_type_questions pivot table the question has the "required" column as "1".

If the user is doing a registration in a conference and the user didn't select ticket/registration type(s) that have custom questions associated the registration works fine, the code enters in the "if ($validator->passes()) {...}".

Issue:

The issue is when there are custom questions associated with one or more selected ticket/registration types.

If there are custom questions that are required I want to validate that also in Laravel. So I have the code below in the storeRegistration() that shows the message "Fill all mandatory fields" if a custom question that is required was not answered.

But even if the user fill all required custom questions the code never enters in the if "if ($validator->passes()) {...}". Do you know why? Also if the question is required and the required attribute is removed from the HTML in the console and the user click in the "Store Registration" the validation errors don't appear.

The code goes always to the else part of the if " "if ($validator->passes()) {...}" and it shows with "else{dd($validator->errors());}":

MessageBag {#278 ▼
  #messages: array:1 [▼
    "participant_question.0" => array:1 [▼
      0 => "The participant question.0 field is required."
    ]
  ]
  #format: ":message"
}

Do you know where is the issue?


The storeRegistrationInfo() that stores the registration and has the validation to check if custom question(s) required were not answered:

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

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

        if (isset($request->participant_question_required)) {

            dd($request->participant_question_required);

            $messages = [
                'participant_question.*.required' => 'Fill all mandatory fields',
            ];

            foreach ($request->participant_question_required as $key => $value) {
                $rule = 'string|max:255'; // I think string should come before max

                // if this was required, ie 1, prepend "required|" to the rule
                if ($value) {
                   $rule = 'required|' . $rule;
                }
                $rules["participant_question.{$key}"] = $rule;
            }
        }

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

        if ($validator->passes()) {
            dd('test');  // this dont appears
            // create an entry in the registrations table
            // create an entry in the participants table for each registered participant
            // create a entry in the answer table for each answer to a custom question
            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,
                          'answer' => $request->participant_question[$key],
                     ]); 
               }
            }
        }
    }

If in the database the questions tables is like:

id      question     conference_id
1        Phone?          1

And in the database pivot table registration_type_questions is:

id  registration_type_id   question_id    required
 1           1                   1             1 

The generated HTML with the getHTMLInput() based on the values of the pivot table and Questions table above is:

<form method="post" id="registration_form" action="http://proj.test/conference/1/conference-test/registration/storeRegistration">
    <input type="hidden" name="_token" value="">
    <p> Is not necessary additional info for the registration. Please just answer the following questions. </p>
     <input type="hidden" value="" name="participant_name[]">
     <input type="hidden" value="" name="participant_surname[]">
    <input type="hidden" name="rtypes[]" value="1">
    <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="submit" class="btn btn-primary" value="Store Registration">
</form>

The method getHtmlInput() that generates the html is in the Question model:

public function getHtmlInput($name = "", $options = "", $required = false, $class = "", $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;
}

Form in the view that uses the getHtmlInput() to generate the html for the custom questions:

<div class="card-body">
    @include('includes.errors')
    <form method="post" id="registration_form" action="{{route('conferences.storeRegistration', ['id' => $id, 'slug' => $slug])}}">
        {{csrf_field()}}
        @if (!is_null($allParticipants) && is_int($allParticipants))
           <!-- If all_participants in conferences table is "1"
                is necessary to collect the name and surname of all participants -->
            @if($allParticipants == 1)
                <p>Please fill the following form.</p>
            @else
               <!-- if is 0 is not necessary to collect the name and surname of each participant 
                    and its used the name and surname of the auth user to do the registration-->
              <!-- the registration types selected by the user can have custom questions associated if don't have no 
                    custom question will appear, if 1 or more registration types have custom questions associated they will
                    appear on the form for the user to answer-->
                @if(collect($selectedRtypes)->first()['questions'] == null)
                    <p>Is not necessary additional info for the registration. </p>
                @else
                    <p>Is not necessary additional info for the registration. Please just answer the following
                        questions.</p>
                @endif
            @endif

            <!-- for each selected ticket is necessary collect the name and surname because all_participants is "1" inside this if -->
            @foreach($selectedRtypes as $k => $selectedRtype)
                @foreach(range(1,$selectedRtype['quantity']) as $val)
                    @if($allParticipants == 1)
                        <h6 class="text-heading-blue mb-3 pb-2 font-weight-bold">
                            Participant - {{$val}} - {{$k}}</h6>
                        <div class="form-group font-size-sm">
                            <label for="name{{ $k }}_{{ $val }}"
                                   class="text-gray">Name</label>
                            <input type="text" id="name{{ $k }}_{{ $val }}"
                                   name="participant_name[]" required
                                   class="form-control" value="">
                        </div>
                        <div class="form-group font-size-sm">
                            <label for="surname{{ $k }}_{{ $val }}"
                                   class="text-gray">Surname</label>
                            <input type="text" id="surname{{ $k }}_{{ $val }}"
                                   required class="form-control"
                                   name="participant_surname[]" value="">
                        </div>
                        <!-- for each registration type if there are custom questions thet will appear so the user can answer -->
                        @foreach($selectedRtype['questions'] as $customQuestion)
                            <div class="form-group">
                                <label for="participant_question">{{$customQuestion->question}}</label>
                                <!--if the custom question is a type checkbox, radio button or select menu-->
                                @if($customQuestion->hasOptions() && in_array($customQuestion->type, ['checkbox', 'radio_btn', 'select_menu']))
                                    {!! $customQuestion->getHtmlInput(
                                        $customQuestion->name,
                                        $customQuestion->options,
                                        ($customQuestion->pivot->required == '1'),
                                        'form-control',
                                        $customQuestion->type)
                                    !!}
                                <!-- if the custom question is of type text, file, textarea -->
                                @else
                                    {!! $customQuestion->getHtmlInput(
                                        $customQuestion->name,
                                        [],
                                        ($customQuestion->pivot->required == '1'),
                                        'form-control',
                                        $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
                    @else
                        <input type="hidden" value=""
                               name="participant_name[]"/>
                        <input type="hidden" value=""
                               name="participant_surname[]"/>
                    @endif
                    <input type="hidden" name="rtypes[]"
                           value="{{ $selectedRtype['id'] }}"/>
                @endforeach
                <!-- is not necessary collect info of each participant and its used the name and surname of the auth user
                    to do the registration -->
                @if ($allParticipants == 0)
                    <!-- if the selected registration types have custom questions associated they will appear in the form
                        so the user can answer -->
                    @foreach($selectedRtype['questions'] as $customQuestion)
                        <div class="form-group">
                            <label for="participant_question">{{$customQuestion->question}}</label>
                            <!-- if the custom question is of type checkbox, radio button or select menu -->
                            @if($customQuestion->hasOptions() && in_array($customQuestion->type, ['checkbox', 'radio_btn', 'select_menu']))
                                {!! $customQuestion->getHtmlInput(
                                    $customQuestion->name,
                                    $customQuestion->options,
                                    ($customQuestion->pivot->required == '1'),
                                    'form-control',
                                    $customQuestion->type)
                                !!}
                            <!-- if the checkbox is of type text, textarea, file-->
                            @else
                                {!! $customQuestion->getHtmlInput(
                                    $customQuestion->name,
                                    [],
                                    ($customQuestion->pivot->required == '1'),
                                    'form-control',
                                    $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
                @endif
            @endforeach
        @endif
        <input type="submit" class="btn btn-primary" value="Store Registration"/>
    </form>
</div>

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

array:1 [▼
  "participant_question.0" => "required|string|max:255"
]

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

array:7 [▼
  "_token" => ""
  "participant_name" => array:1 [▼
    0 => null
  ]
  "participant_surname" => array:1 [▼
    0 => null
  ]
  "rtypes" => array:1 [▼
    0 => "1"
  ]
  "participant_question" => "j"
  "participant_question_required" => array:1 [▼
    0 => "1"
  ]
  "participant_question_id" => array:1 [▼
    0 => "1"
  ]
like image 776
johnW Avatar asked Jun 06 '18 14:06

johnW


2 Answers

According to the documentation:

If you do not want to use the validate method on the request, you may create a validator instance manually using the Validator facade. The make method on the facade generates a new validator instance:

public function store(Request $request)
{
    $validator = Validator::make($request->all(), [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    if ($validator->fails()) {
        return redirect('post/create')
                    ->withErrors($validator)
                    ->withInput();
    }

    // Store the blog post...
}

They don't seem to be passing the Validator as a parameter as you are, rather they are statically calling the function without any reference to the request or any other parameters.

Secondly, consider using the nullable validation flag which allows you to define optional fields.

like image 103
Script47 Avatar answered Sep 29 '22 06:09

Script47


We have a pass method there :

$rules = ['name' => 'unique'];

$input = ['name' => null];

Validator::make($input, $rules)->passes(); // true

So define your rules and number of inputs and give it a go.

You can use dd(Validator::make($input, $rules)->passes();) it will give you true or false, False for not failed validation and true for pass validation.

Further use it like so :

if(Validator::make($input, $rules)->passes(); // true){
    //On pass validation, This section will execute
}
like image 25
Gammer Avatar answered Sep 29 '22 05:09

Gammer