I have something very weird going on with my Laravel application's validation. I have an application where a user can only access it with his/hers unique hash/code in the url. When the url with hash matches a user I prefill the form with the user's profile information. The user then has to confirm/complete/modify it the information in using the form. This works fine, but when submitting the form sometimes the validation not behaving normally.
For example, I leave some fields empty that are required and I submit the form, I get redirected back, my errors are shown in the form fields with a nice red border. All good so far. However, for some unknown reason sometimes when submitting the form with an empty value in a field which is required by the validation, it redirects back and shows the profile form pre-filled again, but the errors variable is empty, but the validation still failed!
Their is no line to draw in when this happens, sometimes it happens on the first submit sometimes I have to submit the form 30 times before it happens. For now we tackled it with an extra layer of frontend validation because the app had to go live, but I can't stop thinking about why and how this is happening.
I'm using a Request class for validation, but I also tried creating a manual validator in my controller, but that has exactly the same behaviour. I first thought that it has something to do with pre-filling the form, so I tried that when there are errors and I don't prefill anything (except input old of course), but the problem still exists.
The weirdest part of it all is that the errors are empty, but some required fields were not filled (and their names are correct) because the problem does not always happens. I have been unable to reproduce the problem on my local and staging env, but it keeps happening on my live server.
It would be great if someone had any suggestions on what I'm doing wrong or what I happening. I did this 1000 of times the only difference with other times is that I prefill the form, but I also have it when I turn that feature off.
Edit: as requested my code below. Note: I replaced some keywords like routes, redirects and relation names.
Request class
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class RegistrationRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'hash' => 'required|exists:users,hash',
'language' => 'required|in:NLD,FRA',
'title' => 'required',
'firstName' => 'required',
'lastName' => 'required',
'street' => 'required',
'postalCode' => 'required',
'city' => 'required',
'email' => 'required|email',
'birthday' => 'required|date_format:d/m/Y',
'tac' => 'required'
];
}
}
Controller method index.
public function index($hash)
{
$user = $this->user->byHash($hash);
if(is_null($user)) {
return redirect()->to('/');
}
if(! is_null($user->myRelationName)) {
return redirect()->route('thanks');
}
return view('my-view', ['user' => $user]);
}
Controller method store
public function store(RegistrationRequest $request)
{
$user = $this->user->byHash($request->hash);
$user->language = $request->language;
$user->title = $request->title;
$user->firstName = $request->firstName;
$user->lastName = $request->lastName;
$user->street = $request->street;
$user->postalCode = $request->postalCode;
$user->city = $request->city;
$user->email = $request->email;
$user->birthday = $request->birthday;
$user->tac = true;
$user->ip = $this->getRemoteIPAddress();
$user->save();
return redirect()->route('my-route', ['hash' => $request->hash]);
}
Vieuw.blade.php
@extends('layouts.master')
@section('content')
<div class="bottom">
<div class="form-container">
<h2>{{trans('merci.register_maintitle')}}</h2>
<p>{!!trans('merci.register_p1')!!}</p>
<p>{!!trans('merci.register_p2')!!}</p>
<h3>{!!trans('merci.register_h3')!!}</h3>
{{ Form::open(['route' => 'register.store', 'class' => 'form', 'id' => "register-form"]) }}
{{Form::hidden('hash', $user->hash, array("id" => "hash"))}}
<div class="form-field-wrap form-group language {{$errors->has('language') ? 'has-error' : null}}">
{{ Form::label('language', trans('merci.register_language'), array('class' => 'form-field-text-label radio-label'))}}
{{ Form::radio('language', trans('merci.register_language1_value'), ($user->language == trans('merci.register_language1_value')) ? true : false, array('id' => 'nl-rad')) }}
<span>{{trans('merci.register_language1_label')}}</span>
{{ Form::radio('language', trans('merci.register_language2_value') , ($user->language == trans('merci.register_language2_value')) ? true : false, array('class' => 'radio', "id"=> 'fr-rad')) }}
<span>{{trans('merci.register_language2_label')}}</span>
</div>
<div class="form-field-wrap form-group title {{$errors->has('title') ? 'has-error' : null}}">
{{ Form::label('title', trans('merci.register_title'), array('class' => 'form-field-text-label radio-label'))}}
{{ Form::radio('title', trans('merci.register_title1_value'), ($user->title == trans('merci.register_title1_value')) ? true : false) }}
<span>{{trans('merci.register_title1_label')}}</span>
{{ Form::radio('title', trans('merci.register_title2_value'), ($user->title == trans('merci.register_title2_value')) ? true : false, array('class' => 'radio')) }}
<span>{{trans('merci.register_title2_label')}}</span>
</div>
<div class="form-field-wrap form-group lastName {{$errors->has('lastName') ? 'has-error' : null}}">
{{ Form::label('lastName', trans('merci.register_lastName'), array('id' => 'lastName', 'class' => 'form-field-text-label'))}}
{{ Form::text('lastName', $user->lastName, array('class' => 'form-field-text-input')) }}
</div>
<div class="form-field-wrap form-group firstName {{$errors->has('firstName') ? 'has-error' : null}}">
{{ Form::label('firstName', trans('merci.register_firstName') , array('class' => 'form-field-text-label'))}}
{{ Form::text('firstName', $user->firstName, array('class' => 'form-field-text-input')) }}
</div>
<div class="extramargin form-field-wrap form-group street {{$errors->has('street') ? 'has-error' : null}}">
{{ Form::label('street', trans('merci.register_street'), array('class' => 'form-field-text-label'))}}
{{ Form::text('street', $user->street, array('class' => 'form-field-text-input big')) }}
</div>
<div class="smallerpostal form-field-wrap form-group postalCode {{$errors->has('postalCode') ? 'has-error' : null}}">
{{ Form::label('postalCode', trans('merci.register_postalCode'), array('class' => 'form-field-text-label smaller-label'))}}
{{ Form::text('postalCode', $user->postalCode, array('class' => 'form-field-text-input smaller')) }}
</div>
<div class="smallercity form-field-wrap form-group city {{$errors->has('city') ? 'has-error' : null}}">
{{ Form::label('city', trans('merci.register_city'), array('class' => 'form-field-text-label smal-label'))}}
{{ Form::text('city', $user->city, array('class' => 'form-field-text-input smal')) }}
</div>
<div class="extramargin form-field-wrap form-group email {{$errors->has('email') ? 'has-error' : null}}">
{{ Form::label('email', trans('merci.register_email'), array('class' => 'form-field-text-label'))}}
{{ Form::email('email', $user->email, array('class' => 'form-field-text-input ')) }}
</div>
<div class="form-field-wrap form-group birthday {{$errors->has('birthday') ? 'has-error' : null }} ">
{{ Form::label('birthday', trans('merci.register_birthday'), array('class' => 'form-field-text-label', "id" => "birthdate"))}}
{{ Form::text('birthday', $user->birthday, array('class' => 'form-field-text-input', "id"=>"datepicker")) }}
</div>
<div class="check form-field-wrap form-group tac {{$errors->has('tac') ? 'has-error' : null }}">
{{ Form::checkbox('tac', trans('merci.register_tac_value'), false, array('class' => 'form-field-checkbox', "id" => "tac"))}}
{{ Form::label('tac', trans('merci.register_tac_label'), array('class' => 'form-field-error-label')) }}
<span>{!!trans('merci.register_tac_label_link')!!}</span>
</div>
@if (count($errors) > 0)
<div id="error server" style='display:none;'>
@else
<div id="error" style='display:none;'>
@endif
<p class="error">{{trans('merci.register_error')}}</p>
</div>
{!! Form::submit(trans('merci.register_submit'), array('class' => 'btn-main btn')) !!}
{{ Form::close() }}
<small>{{trans('merci.register_mandatory')}}</small>
</div>
</div>
<script src="{{ asset('js/validate.js') }}"></script>
@stop