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
I don't know if your routes are inside the web middleware, but if you are losing the $errors bag variable, that could be the cause.
Any routes not placed within the web middleware group will not have
access to sessions and CSRF protection (See the default routes file).
When $errors variable is bound to the view by the web middleware group this variable will always be available in your views. (See Displaying The Validation Errors).
// Make sure any routes that need access to session features are placed within
Route::group(['middleware' => 'web'], function () {
Route::get('/', 'MyController#index');
});
Also, I would use the old helper in the blade template to retrieve flashed input from the previous request.
{{ old('username') }}
Related
I have this code for my form and it works well:
<div class="form-group">
<select class="form-control" id="exampleSelect1">
<option>Assign</option>
#foreach ($projects as $project)
<option>{{ $project->name }} </option>
#endforeach
</select>
</div>
but what I'm trying to do is this with a contact form:
<div class="form-group">
{!! Form::label('name', 'Project') !!}
{!! Form::select (#theforeach with the values :c ) !!}}
</div>
I'm using the use App\Http\Requests\ContactFormRequest; and I have been searching the way of doing it but there is to few examples on google.
Form is part of the Laravel Collective HTML library, you can find the documentation here, specifically you're looking for the Select documentation:
echo Form::select('size', ['L' => 'Large', 'S' => 'Small']);
You have a Collection of Project models, each with a name and (presumably) an id which you need to turn into a key -> value array for the select method which you can do using pluck:
{!! Form::select('project', $projects->pluck('name', 'id')) !!}
Then within your controller you'll be able to find the project that has been selected using find, e.g:
Project::find($request->project);
If you want your select options to works, you need to call it properly,
From controller,
// Example : This is for single view page
$list_of_options = Products::pluck('name','id');
return view('your_view_name',compact('list_of_options'));
// Example : If you want select dropdown in all page ( within the controller views) then,
use Illuminate\Support\Facades\View;
public function __construct(){
View::share('list_of_options',Products::pluck('name','id'));
}
Now in blade,
{{ dd($list_of_options); }} // Check if the values are comming in proper formate
{!! Form::select('name_of_the_select', $list_of_options, null ,[
'class' => 'form-control',
'id' => 'name_of_the_select'
]);
!!}
Here is the button with <i> or <span> inside of it :-
{{ Form::button(
'<span class="fa fa-play fa-1x"></span>',
[
'class'=>'btn btn-info',
'type'=>'button'
])
}}
From your question ( UPDATED )
<div class="form-group">
{!! Form::label('exampleSelect1', 'Project') !!}
{!! Form::select('projects', $projects, null ,[
'class' => 'form-control',
'id' => 'exampleSelect1',
'placeholder' => 'Please select project'
]);
!!}
</div>
I hope this helps. :)
Try this
<div class="form-group">
{!! Form::label('project', 'Project') !!}
{!! Form::select ('project', $projects->pluck('name')) !!}}
</div>
See docs https://laravel.com/docs/4.2/html#drop-down-lists
<div class="form-group">
{!! Form::label('project', 'Project') !!}
{!! Form::select ('project', $projects->pluck('name', 'id')) !!}}
</div>
When a user is created a random password (and a auth code) will be created and send with an email to the user.
When clicked on the link in the email the user status will be 1 (so active) and the user will be able to change his password right away.
Now it doesn't work as I want to.
UserController:
public function store(CreateUserRequest $request, User $user, Attribute $attribute)
// some unnecessary code
if ((Input::get('usertype_id')) > 1) {
$randomPassword = str_random(8);
$user->password = Hash::make($randomPassword);
$authentication_code = str_random(12);
$user->authentication_code = $authentication_code;
$user->active = 0;
};
$user->save();
if ((Input::get('usertype_id')) > 1) {
// Email sturen met verficatie code
$email = Input::get('email');
Mail::send('emails.user', ['user' => $user, 'password' => $randomPassword, 'authentication_code' => $authentication_code], function ($message) use ($email) {
$message->to($email, 'Lilopel')->subject('Lilopel: Verify your account!');
});
};
public function confirmUser($authentication_code)
{
if (!$authentication_code)
{
return 'auth code not found!';
}
$user = User::where('authentication_code', '=', $authentication_code)->first();
if (!$user)
{
return 'user not found!';
}
$user->active = 1;
$user->save();
Session::put('user_id', $user->id);
return view('user.setpassword', ['user' => $user]);
//return redirect()->route('user.setPassword', [$user_id]);
}
public function setPassword(SetPasswordRequest $request)
{
$user_id = Session::get('user_id');
$user = $this->user->find($user_id);
$user->fill($request->only('password'));
$user->save();
}
Route:
Route::get('user/verify/{authenticationCode}', 'UserController#confirmUser');
Route::get('user/password', 'UserController#setPassword');
View:
{!! Form::model($user, ["route"=>['user.setPassword', $user->id] , "method" => 'PATCH']) !!}
<div class="form-group {{ $errors->has('password') ? 'has-error' : '' }}">
{!! Form::label('password', trans('common.password'), ['class' => 'form-label col-sm-3 control-label
text-capitalize']) !!}
<div class="col-sm-6">
{!! Form::password('password', ['name' => 'password', "class"=>"form-control","placeholder" =>
trans('common.password') ]) !!}
{!! $errors->first('password', '<span class="help-block">:message</span>') !!}
</div>
</div>
<div class="form-group {{ $errors->has('confirm_password') ? 'has-error' : '' }}">
{!! Form::label('password_confirmation', trans('common.confirmpassword'), ['class' => 'form-label
col-sm-3 control-label text-capitalize']) !!}
<div class="col-sm-6">
{!! Form::password('password_confirmation', ['name' => 'password_confirmation',
"class"=>"form-control","placeholder" => trans('common.confirmpassword') ]) !!}
{!! $errors->first('password_confirmation', '<span class="help-block">:message</span>') !!}
</div>
</div>
{!! Form::submit( trans('common.edit'), ["class"=>"btn btn-primary text-capitalize center-block "]) !!}
{!! Form::close() !!}
Email links works, the status of the user gets active, but then the .blade will give a Route [user.setPassword] not defined. (View: public_html/server2/resources/views/user/setpassword.blade.php) error.
work togetherTo use the route as you do, you need a named route.
Change this
Route::get('user/password', 'UserController#setPassword');
to this
Route::get('user/password', [
'as' => 'user.setPassword',
'uses' => 'UserController#showProfile'
]);
Also, make sure the HTTP verbs of the route and your form's method work together.
EDIT
This issue has been solved, but I don't understand why the answer worked.
I would like to know why it didnt work.
Is there some one who could explain me?
Original question
I am stuck on my settings form, my problem is that at the settings form you can enter some email settings but you can also change your password.
The email settings and password reset works and my form fills it self with the data of the current user. But when the form validation fails it redirecteds me back to the form without the form data.
I am not sure if I made myself clear, but this code below will explain it.
ChangeUserSettingRequest.php
class ChangeUserSettingsRequest extends Request {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
if (\Auth::check()) {
return true;
}
return false;
}
/**
* Get the validation rules that apply to the request.
*
* WHEN THIS VALIDATION FAILS IT GOES BACK TO SETTINGS.BLADE.PHP
* BUT IT DOES NOT KEEP THE SETTINGS DATA IN THE FORM
*/
public function rules()
{
return [
'current_password' => 'sometimes|required_with:password',
'password' => 'required_with:current_password|min:8|confirmed',
'password_confirmation' => 'required_with:password',
];
}
}
settings.blade.php
{!! Form::model($settings, array('url' => route('store.settings'), 'class' => 'col s12')) !!}
<p>#lang('forms.info.settings')</p>
<div class="input-field col s12 m6 l6">
{!! Form::checkbox('info_mail', 0, false, ['id' => 'info_mail']) !!}
{!! Form::label('info_mail', Lang::get('forms.newsletter'), ['for' => 'info_mail']) !!}
</div>
<div class="input-field col s12 m6 l6">
{!! Form::checkbox('message_notification', 0, false, ['id' => 'message_notification']) !!}
{!! Form::label('message_notification', Lang::get('forms.messages'), ['for' => 'message_notification']) !!}
</div>
<div class="input-field col s12 m6 l6">
{!! Form::checkbox('friend_notification', 0, false, ['id' => 'friend_notification']) !!}
{!! Form::label('friend_notification', Lang::get('forms.friendrequest'), ['for' => 'friend_notification']) !!}
</div>
<div class="input-field col s12 m6 l6">
{!! Form::checkbox('item_notification', 0, false, ['id' => 'item_notification']) !!}
{!! Form::label('item_notification', Lang::get('forms.reactiononitem'), ['for' => 'item_notification']) !!}
</div>
#if ($settings and $settings->google_maps !== null)
<div class="settings-explain">
<p class="margin-top-20">#lang('forms.info.companysettings')</p>
</div>
<div class="input-field col s12 m6 l6">
{!! Form::checkbox('type', 0, false, ['id' => 'type']) !!}
{!! Form::label('type', Lang::get('forms.companytype'), ['for' => 'type']) !!}
</div>
<div class="input-field col s12 m6 l6">
{!! Form::checkbox('google_maps', 0, false, ['id' => 'google_maps']) !!}
{!! Form::label('google_maps', Lang::get('forms.companymap'), ['for' => 'google_maps']) !!}
</div>
#endif
<div class="settings-explain">
<p class="margin-top-20">#lang('forms.info.changepassword')</p>
</div>
<div class="input-field col s12">
{!! Form::label('current_password', $errors->has('current_password') ? $errors->first('current_password') : Lang::get('forms.currentpassword'), ['for' => 'current_password']) !!}
{!! Form::password('current_password', ['class' => $errors->has('current_password') ? 'invalid' : '']) !!}
</div>
<div class="input-field col s12">
{!! Form::label('password', $errors->has('password') ? $errors->first('password') : Lang::get('forms.newpassword'), ['for' => 'password']) !!}
{!! Form::password('password', ['class' => $errors->has('password') ? 'invalid' : '']) !!}
</div>
<div class="input-field col s12">
{!! Form::label('password_confirmation', $errors->has('password_confirmation') ? $errors->first('password_confirmation') : Lang::get('forms.repeatpassword'), ['for' => 'password_confirmation']) !!}
{!! Form::password('password_confirmation', ['class' => $errors->has('password_confirmation') ? 'invalid' : '']) !!}
</div>
<div class="input-field col s12">
{!! Form::button(Lang::get('forms.save'), ['class' => 'btn waves-effect waves-light', 'type' => 'submit', 'name' => 'Save']) !!}
</div>
{!! Form::close() !!}
UserInfoController.php
/**
* Function shows the settings form
*/
public function showSettings()
{
$title = Lang::get('titles.settings');
$user_id = Auth::User()->id;
$settings = $this->settings->getUserSettings($user_id);
$companySettings = $this->companySettings->getSettings($user_id);
if ($companySettings) {
$settings->type = $companySettings->type;
$settings->google_maps = $companySettings->google_maps;
}
return view('pages.users.settings', ['title' => $title])->with(compact('settings'));
}
/**
* Function stores the setting changes
*
* ChangeUserSettingsRequest makes sure that the request is valid
*/
public function storeSettings(ChangeUserSettingsRequest $request)
{
$id = Auth::User()->id;
$success = $this->settings->handleStoreSettingsRequest($request);
// Checks if user has company settings
$hasCompanySettings = $this->companySettings->checkForSettings($id);
// If user has company settings
if ($hasCompanySettings === true) {
// Update company settings
$this->companySettings->updateSettings($request);
}
if ($success === true) {
/* Get translated message */
$message = Lang::get('toast.settingsstored');
return Redirect::route('user.profile', array(Auth::User()->permalink))->withMessage($message);
}
$settings = $this->settings->getUserSettings($id);
/* Get translated message */
$message = Lang::get('forms.error.wrongpassword');
/* This works and the form is filled with the correct data after it redirects me back */
return Redirect::back()->withErrors(array('current_password' => $message))->withSettings($settings);
}
Request.php
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest {
//
}
So my problem is that in my UserInfoController I redirect back and it has the good data but when my ChangeUserSettingsRequest redirects me back the form is empty.
Does anyone know why ChangeUserSettingsRequest does not send the data back?
I am not talking about the password data but about the email settings.
I do not want to make a costum validator as I think this should be posible.
Please note: when the validation fails, the function storeSettings will not be executed at all
On failure return them back to the page with their input data (withInput())
return Redirect::back()->withErrors(['current_password' => $message])->withInput($request->except('password'));
For more information see the Laravel docs pertaining to requests... http://laravel.com/docs/5.1/requests
I found it!
The formRequest should have handled it correctly but no idea why it did not.
I found the solution when looking trough the file formRequest.php
https://github.com/laravel/framework/blob/master/src/Illuminate/Foundation/Http/FormRequest.php
I had to override the response function and it works now!
To only thing that I had to add to my ChangeUserSettingsRequest was this
public function response(array $errors)
{
return $this->redirector->to($this->getRedirectUrl())->withErrors($errors, $this->errorBag);
}
The only difference is that I don't send the input fields back, little strange that this works but I am glad that it is solved now.
I'm having problems populating values of my inputs when I have eloquent queries using with(
Controller:
private $viewPath = "pages.person.";
public function edit($id)
{
$person = Person::where('id', '=', $id)->with('Email', 'Phone', 'User', 'Client', 'JuridicPerson.TypeActivities')->firstOrFail();
$this->setData('person', $person); // Set information to be used in the creation of `views` and `nest.views`.
$this->setData('users', User::lists('name', 'id'), ['0' => 'Select…']); // Set information to be used in the creation of `views` and `nest.views`.
return $this->view($this->viewPath.'edit'); // Register a new view.
}
My views are made in a way that I share the form between my edit and my create. So I have create.blade.php, edit.blade.php and both made a call to form.blade.php this I can not change.
My edit.blade
{{ Form::model($person, array('method' => 'PATCH', 'class' => 'defaultForm', 'route' => array('person.update', $person->id))) }}
#include('pages.person.form')
{{ Form::close() }}
My form.blade
<!-- This input brings the correct value -->
<div class="row">
<div class="col-md-12">
{{ Form::input('name', 'name', null, ['class' => 'form-control', 'placeholder' => 'Nome', 'maxlength' => 35, 'required', 'autofocus']) }}
</div>
</div>
<!-- This input value is empty -->
<div class="row">
<div class="col-md-12">
{{ Form::textarea('Client[observation]', null, ['class' => 'form-control', 'placeholder' => 'Observations']) }}
</div>
</div>
But if I add this piece of code anywhere in my html, I get the correct value in client...
{{ $person->client }}
Not sure what should I do to fix my code, the data is correct, when I print the data (above code) the inputs output the correct value (but I can't have the the return printed on the screen for the user).
What I need is to print the correct value into the correct input.
Use client rather than Client when loading that relationship.
When you did {{ $person->client }} it had the side effect of loading that client relationship so it could be used.
When loading relationships, you should use the name of the function, exactly, that's responsible for setting up those relationships.
I am in the progress of making a form to edit an existing entry in the database. I am using the Form::model approach to do this, however it doesn't seem to work. The fields just stay empty.
ServerController.php
/**
* Editing servers
*/
public function edit($name)
{
$server = Server::find($name);
$keywords = ($server->getKeywords()) ? $server->getKeywords() : array();
$countries = $this->getCountries();
return View::make('server/edit', array('server' => $server, 'countries' => $countries));
}
public function update($name)
{
$server = Server::find($name);
// Did it succeed?
if($server->save()) {
Session::flash('success', 'You server was edited!');
return Redirect::route('server.view', array($name));
}
// Did not validate
if(Input::get('keywords')) {
$keywords = Input::get('keywords');
Session::flash('keywords', $keywords);
}
Session::flash('danger', "<b>Oops! There were some problems processing your update</b><br/>" . implode("<br/>", $server->errors()->all()));
return Redirect::route('server.edit', array($name))->withInput()->withErrors($server->errors());
}
The Form
{{ Form::model($server, array('route' => array('server.update', $server->name), 'class' => 'form-horizontal', 'role' => 'form', 'files' => true)) }}
<div class="form-group {{ $errors->has('email') ? 'has-error' : '' }}">
{{ Form::label('email', 'Email', array('class' => 'control-label col-md-4')) }}
<div class="col-md-4">
{{ Form::text('email', '', array('class' => 'form-control')) }}
{{ $errors->first('email', '<br/><div class="alert alert-danger">:message</div>') }}
</div>
</div>
(some more fields)
{{ Form::close() }}
The problem here is that you're passing in an empty string as the default field value. As the documentation states here, any explicitly passed values will overrule the model attribute data. Try using null instead of '':
{{ Form::text('email', null, array('class' => 'form-control')) }}