What I have
I have a form with 3 inputs and I want to check the following conditions:
All inputs are integers and they are required.
We do a math operation with all the numbers and we get if the operation was successfull or not.
Success: we redirect the user to a success page.
No success: we show a error message to the user with a message explaining him that the numbers aren't valid.
I resolved this with the following lines.
Controller:
function formAction(Request $request) {
$this->validate($request, [
'number1' => 'integer|required',
'number2' => 'integer|required',
'number3' => 'integer|required',
]);
$numbers = $request->all();
$isValid = MyOwnClass::checkMathOperation($numbers);
if($isValid) {
return redirect()->route('success');
} else {
$request->session()->flash('error', 'The numbers are not valid.');
return back();
}
}
View (using Bootstrap):
<form method="POST" action="{{ route('form-action') }}">
#csrf
<div class="form-group">
<label for="number1">number1</label>
<input id="number1" name="number1" class="form-control {{ $errors->has('number1') ? ' is-invalid' : '' }}" />
</div>
<div class="form-group">
<label for="number2">number2</label>
<input id="number2" name="number2" class="form-control {{ $errors->has('number2') ? ' is-invalid' : '' }}" />
</div>
<div class="form-group">
<label for="number3">number3</label>
<input id="number3" name="number3" class="form-control {{ $errors->has('number3') ? ' is-invalid' : '' }}" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
What I looking for
When MyOwnClass::checkMathOperation($numbers) is false:
To highlight number1, number2 and number3 inputs.
To show an unique custom error message
To hide the number1, number2 and number3 input error messages.
How can I do that with validators?
Solution
Create a Form Request Validation called, for example, NumbersForm using:
php artisan make:request NumbersForm
The previous command creates a App/Http/Requests/NumbersForm.php file. Make authorize() returns true, put the validation rules into rules() and create a withValidatior() function.
class NumbersForm extends FormRequest
{
public function authorize() {
return true;
}
public function rules() {
return [
'number1' => 'integer|required',
'number2' => 'integer|required',
'number3' => 'integer|required',
];
}
public function withValidator($validator) {
$validator->after(function ($validator) {
$numbers = $this->except('_token'); // Get all inputs except '_token'
$isValid = MyOwnClass::checkMathOperation($numbers);
if(!$isValid) {
$validator->errors()->add('number1', ' ');
$validator->errors()->add('number2', ' ');
$validator->errors()->add('number3', ' ');
$validator->errors()->add('globalError', 'The numbers are not valid.');
}
});
}
}
Note: It's not important the text in the second param of $validator->errors()->add('number1', ' ');, but it can't be empty. If it is an empty string, $errors->has('number1') returns false, and the field won't be hightlighted.
Set the controller like this:
use App\Http\Requests\NumbersForm;
function formAction(NumbersForm $request) {
$this->validated();
return redirect()->route('success');
}
And, finally, if we want to print an unique error message, we must remove the following lines from view:
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
and replace them with:
#if ($errors->has('globalError'))
<div class="alert alert-danger">
{{ $errors->first('globalError') }}
</div>
#else
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
#endif
I haven't tested this but I think it can get you going in the right direction.
1 // Highlight the inputs
You can do this by accessing the error object within your view. This object is an instance of the MessageBag object.
Here is the docs: https://laravel.com/docs/5.7/validation#working-with-error-messages
Example:
// if the error exists for the input the class will be added
<input class=" {{ $error->has('number1') ? 'highlight' : '' }}" name="number1">
<input class=" {{ $error->has('number2') ? 'highlight' : '' }}" name="number2">
<input class=" {{ $error->has('number3') ? 'highlight' : '' }}" name="number3">
2 & 3 // Show a unique custom error message and hide the default messages
See the validator docs: https://laravel.com/docs/5.8/validation#custom-error-messages && https://laravel.com/docs/5.7/validation#working-with-error-messages -- this should solve both of these.
There is a validator callback and I think you can pass your second validation into that. If these numbers aren't valid then you can add your custom error messages and access them the same way as I did above.
function formAction(Request $request) {
$validator = $this->validate($request, [
'number1' => 'integer|required',
'number2' => 'integer|required',
'number3' => 'integer|required',
]);
$validator->after(function ($validator) {
$numbers = $request->all();
$isValid = MyOwnClass::checkMathOperation($numbers);
if(!$isValid) {
$validator->errors()->add('number1', 'Unique message');
$validator->errors()->add('number2', 'Unique message');
$validator->errors()->add('number3', 'Unique message');
}
});
}
Custom Validation Rules:
To add custom messages and validation you can also write a custom validation rule
Example:
class Uppercase implements Rule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
return strtoupper($value) === $value;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The :attribute must be uppercase.';
}
}
Custom Error Messages:
You could also add custom error messages for rules within a Request:
public function messages()
{
return [
'number1.required' => 'My custom message telling the user he needs to fill in the number1 field.',
'number1.integer' => 'My custom message telling the user he needs to use an integer.',
];
}
Related
I'm trying to validate a field for unique value. The validate function throws proper validation errors When I enter incorrect/duplicate values but the execution got stuck in validate method and not coming below to dd('save called') when I enter correct/unique values.
I have tried protected $rules[], and protected function rules() but result is the same.
Note: when I remove the unique rule from validation then everything works fine.
here is component code.
public function savePaper($rowIndex)
{
$this->validate([
'rows.*.p1' => ['required', Rule::unique('dutysheets', 'p1')->ignore($this->row['id'])],
]);
dd('save called');
$row = $this->rows[$rowIndex] ?? NULL;
if (!is_null($row)) {
optional(DutySheet::find($row['id']))->update($row);
}
$this->editedRowIndex = null;
$this->editedPaper = null;
}
and here is the view code.
#foreach ($rows as $index => $row)
<tr>
<td scope="row">
<input type="number" style="max-width: 60px;"
wire:model.differ="rows.{{ $index }}.p1"
wire:click="editPaper({{ $index }}, 'p1')"
wire:keydown.enter="savePaper({{ $index }})"
/>
#if ($editedPaper === $index . '.p1')
#error('rows.' . $index . '.p1')
<div class="alert alert-danger">
{{ $message }}
</div>
#enderror
#endif
</td>
Error messages are not showing.I added the redirection in
sendFailedLoginResponse it is redirecting to the login page without error messages
protected function sendFailedLoginResponse(Request $request)
{
return redirect()->route("login")->withErrors([
$this->username() => [trans('auth.failed')],
]);
}
Blade
<div class="form-group col-md-12">
<input id="email" name="email" class="" type="email" placeholder="Your Email">
#if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
</span>
#endif
return redirect()->route("login")->withErrors(['email' => trans('auth.failed')]);
Instead of array pass a message bag object like this.
$errors = new Illuminate\Support\MessageBag;
$errors->add('email', trans('auth.failed'));
return redirect()->route("login")->withErrors($errors);
The name of the input field should be the second argument of the withErrors() function.
Laravel documentation - Manually Creating Validators
protected function sendFailedLoginResponse(Request $request)
{
return redirect()->route("login")->withErrors(trans('auth.failed'), 'login');
}
Blade file
<div class="form-group col-md-12">
<input id="email" name="email" class="" type="email" placeholder="Your Email">
#if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->login->first('email') }}</strong>
</span>
#endif
If Your application is too large folow these steps
While You are making the validation there are several ways
Method one
Using Validator Facade
public function store(Request $request)
{
$input = $request->all();
$validator = \Validator::make($input, [
'post_name' => 'required',
'post_type' => 'required',
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput($input);
}
Post::create($input);
return redirect('post.index');
}
Method Two
using $this->validate(); Method
public function store(Request $request)
{
$this->validate($request, [
'post_name' => 'required',
'post_type' => 'required',
]);
Post::create($request->all());
}
Method Three
Using the request method
php artisan make:request PostStoreRequest
anf the file will be creted in app\Http\Requests with name PostStoreRequest.php
open you controller and add
use App\Http\Requests\PostStoreRequest;
now the file contents
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class PostStoreRequest extends FormRequest
{
/**
* 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 [
'post_name' => 'required',
'post_type' => 'required',
];
}
/**
* Custom message for validation
*
* #return array
*/
public function messages()
{
return [
'post_name.required' =>'Enter Post Name',
'post_type.required' =>'Enter Post Type',
];
}
}
if You want to customize the error message use messages function
now the store function
public function store(PostStoreRequest $request)
{
Post::create($request->all() );
return redirect()->route('post.index')->with('success','CrmHfcImageGallery Created Successfully');
}
now Comming to the view
to view all the messages add this in top of the blade file
#if ($errors->any())
{{ implode('', $errors->all('<div>:message</div>')) }}
#endif
To view particular message
<div class="col-sm-4">
<div class="form-group #if ($errors->has('post_name')) has-error #endif">
{!! Form::label('post_name','Post Name') !!}
{!! Form::text('post_name',old('post_name'),['placeholder'=>'Enter Post Name ','class' =>'form-control rounded','id' =>'post_name']) !!}
#if ($errors->has('post_name'))
<p class="help-block">{{ $errors->first('post_name') }}</p>
#endif
</div>
</div>
Hope it helps
I am trying to return a flash message depending on the outcome of an function however I don't really know how to do this properly, can someone help me with fixing this?
Controller:
public function postDB(Requests\NameRequest $request) {
$newName = trim($request->input('newName'));
$newLat = $request->input('newCode');
$websites = new Website();
$websites->name = $newName;
$websites->html = $newLat;
$websites->save();
if ($websites->save())
{
$message = 'success';
}else{
$message = 'error';
}
return redirect()->back()->withInput()->with('message', 'Profile updated!');
}
Request:
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'img' => 'file|image',
];
}
public function messages()
{
return [
'img.image' => 'File type is not supported! Use files with extension .jpg/.jpeg/.gif',
];
}
Template:
#if (session('status'))
#if (session('status')=="success")
<div class="alert alert-success">
{{ session('message') }}
</div>
#else
<div class="alert alert-error">
{{ session('message') }}
</div>
#endif
#endif
Route:
Route::group(['middleware' => ['web']], function () {
Route::get('home', 'BuilderController#homepage');
Route::get('pages', 'BuilderController#websites');
Route::get('template', 'BuilderController#templates');
Route::post('template2', 'BuilderController#postDB');
Route::post('template', 'BuilderController#testing');
Route::get('logout', 'BuilderController#getLogout');
Route::get('/website/{name}', 'BuilderController#website');
});
Solution :
There could be only one reason for this issue.
The laravel will pass the flash messages only if it's registered inside the middleware web
i.e.,
Route::group(['middleware' => ['web']], function () {
//The back()'s url should be registered here
});
Update :
It seems you need to redirect back with message and inputs
So, You can do like this
if ($request->hasFile('img')) {
$message = 'success';
} else {
$message = 'error';
}
return redirect()->back()->withInput()->->with('message', $message);
Update 2 :
#if (session('status'))
#if (session('status')=="success")
<div class="alert alert-success">
Congrats! Everything was fine
</div>
#else
<div class="alert alert-error">
Oops! Something went wrong
</div>
#endif
#endif
Note : You can pass the status param to your wish
If you pass message as a flash parameter name, use it, not status.
#if (session('message'))
#if (session('message')=="success")
<div class="alert alert-success">
Congrats! Everything was fine
</div>
#else
<div class="alert alert-error">
Oops! Something went wrong
</div>
#endif
#endif
I created a validation but cant show it on view, its important to return search view and don't redirect back user. help me please, thanks all?
Controller :
public function search(Request $request)
{
$msg = Validator::make($request->all(), [
'search' => 'required'
]);
if ($msg->fails()) {
return view('layouts.search')->withErrors($msg->messages());
} else {
return "Thank you!";
}
}
View :
#if($errors->any())
<ul class="alert alert-danger">
#foreach($errors as $error)
<li> {{$error}} </li>
#endforeach
</ul>
#else
You can use $error->first('name_of_error_field') to show error messages.
You can do it like this:
public function search(Request $request)
{
$validator = Validator::make($request->all(), [
'search' => 'required'
]);
if ($validator->fails()) {
return view('layouts.search')->withErrors($validator); // <----- Send the validator here
} else {
return "Thank you!";
}
}
And in view:
#if($errors->any())
<ul class="alert alert-danger">
#foreach($errors as $error)
<li> {{$error->first('name_of_error_field')}} </li>
#endforeach
</ul>
#endif
See more about Laravel Custom Validators
Hope this helps
I'm trying to combine all NotBlank error messages into one.
If the error array contains at least 1 error that is a NotBlank type, I want it to display only one message like "Please fill in all fields."
How can I do this?
Here's my twig code
{{form_start(form, {'attr': {'novalidate': 'novalidate'}})}}
<div>
{{form_widget(form.firstName)}}
{{form_widget(form.lastName)}}
</div>
<div>
{{form_widget(form.username)}}
{{form_widget(form.email)}}
</div>
<div>
{{form_widget(form.password.first, {'attr' : { 'placeholder' : 'Password' } })}}
{{form_widget(form.password.second, {'attr' : { 'placeholder' : 'Confirm Password' } })}}
</div>
<div>
{{form_label(form.birthday)}}
</div>
<div>
{{form_widget(form.birthday)}}
</div>
<div>
{{form_widget(form.gender)}}
</div>
<div>
{{form_widget(form.save)}}
</div>
{{ form_errors(form.firstName) }}
{{ form_errors(form.lastName) }}
{{ form_errors(form.username) }}
{{ form_errors(form.email) }}
{{ form_errors(form.password.first) }}
{{form_end(form)}}
You can create a CallbackValidator
http://symfony.com/doc/current/reference/constraints/Callback.html
and in the validate method, check if at least one of the desired fields is blank, and if true, call
/**
* #Assert\Callback
*/
public function validate(ExecutionContextInterface $context)
{
if(empty($this->field1) || empty($this->field2)) {
$context->addViolation($message);
}
}
This way you will receive a global form error.