With Laravel 8.x it appears from the docs snippet below that using old() for the old input value is not necessary but I can't figure out how to not use it.
Laravel allows you to keep input from one request during the next request. This feature is particularly useful for re-populating forms after detecting validation errors. However, if you are using Laravel's included validation features, it is unlikely you will need to manually use these methods, as some of Laravel's built-in validation facilities will call them automatically.
https://laravel.com/docs/8.x/requests#old-input
I know I can do <input name="field" value="{{ old('field') }}" /> but I'm unclear if that is the best / accepted way to include the original posted value during form validation errors.
I also tried this per another SO post:
$validationRules = [
'field' => 'required|max:255',
];
$validator = Validator::make($request->all(), $validationRules);
if ($validator->fails()) {
return redirect(route('item.create'))->withInput()->withErrors($validator);
}
Can anyone shed some light on this?
$validationRules = [
'field' => 'required|max:255',
];
$validator = Validator::make($request->all(), $validationRules);
if ($validator->fails()) {
//Add the $request->flash() to include the errors
$request->flash();
return redirect(route('item.create'))->withErrors($validator);
}
Related
I did move from Lumen to Laravel and now converting my project over. Everything is working except the validation. For some reason, if I try to validate, it just redirects to the welcome.blade.php view. What could cause this?
I am using only the API part of routes, not the view. I am not dealing with views. I am using the stateless part of Laravel.
According to documentation, I can validate like this:
$this->validate($request, [
'title' => 'required|unique|max:255',
'body' => 'required',
]);
If validation passes, your code will keep executing normally. However,
if validation fails, an
Illuminate\Contracts\Validation\ValidationException will be thrown.
I also tried to force it to return JSON response without success:
$validator = $this->validate($request, ['email' => 'required']);
if ($validator->fails()) {
$messages = $validator->errors();
return new JsonResponse(['status' => 'error', 'messages' => $messages]);
}
However, mine doesn't fail but just returns the welcome view with response code of 200. I have tried pretty much all the possible validation methods from the documentation and from google. Non of them are working.
I even tried with clean laravel install, declared one test route and test controller which had the validation and the result is the exact same.
Is the validation even meant to be compatible with the restful/stateless part of Laravel?
Any suggestion is much appreciated.
1- first the unique key needs a table, per example if you want the email to be unique in the users table you do as follows:
'email' => 'required|unique:users',
I think may be you have placed your route in route/web.php file. Replace that code from web.php to api.php
Try to place your API endpoints in route/api.php file.
And remember you need to add prefix /api in your route.
Ex : test.com/api/users.
I am trying to submit a form and validate the content.
In one of the requests I need to make a special rule.
I followed the documentation and it says to use unique and declare a Rule.
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
I am trying with the example from the documentation, but all I get it this error:
Class 'Illuminate\Validation\Rule' not found
I declared the line
use Illuminate\Validation\Rule;
In my controller, but the error is still there.
The Rule class in the example you posted is for validate an unique field. For examplo if you have an email you will want to be unique in the table, when you are going to edit the record, at saving, will get a validator error because you are saving the same email it is already in the db.
The example you posted:
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
is related to this case, editing a record and validating the email (unique in table users). This example avoid to validate the email against the same user-
For using it you have to add the class (not included in the laravel installator). Here you have it.
In your question you say about using the unique rule. The unique rule is for fields that has to be unique in a table, an email, an personal identification (law), and more. Verify if the unique rule is what you need.
You dont have to use the Rule class for this.
Simply achieve the same with following rule:
'email' => 'required|unique:users,email,' . $user->id
The Illuminate\Validation\Rule class has been added on Laravel 5.3+.
I almot sure you have tested with an old laravel version.
See issue (PR) 15809: [5.3] Object based unique and exists rules for validation.
I had that problem on version v5.3. I just updated to the latest patch version (v5.3.31 in my case) and all worked correctly!
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
You have done everything ok so far until you add the line
"Rule::unique('users')->ignore($user->id)"
The only reason why this is not working is because you are not specifying the column name you want to be unique. Let's assume that, in your database, the column name of the table users that you want to be unique is "email". Then, your code should be as follows:
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users', 'email')->ignore($user->id),
],
]);
Thus,
//Right Way
"Rule::unique('users', 'email')->ignore($user->id)"
//Wrong Way
"Rule::unique('users')->ignore($user->id)"
Why don't you try in you method something like this:
$validator = Validator::make($request->all(), [
'email' => 'required|unique:<table_name>',
]);
if ($validator->fails()) {
...
}
If you column if also named email laravel will know automaticly, else do
required|unique:<table_name>,<column_name>
Here is a link to the documentation validation section: https://laravel.com/docs/5.3/validation
I am integrating Amazon MWS in Laravel, so far so good, Now, in my dashboard, I have created a form where user can put his Seller ID and Auth Token ( provided by Amazon). My code looks like this
$store = StoreController::Find($id)->first();
$this->validate($request, [
'name' => 'required|max:255',
'merchantId' => 'required|max:255',
'authToken' => 'required|max:255',
'marketplaceId' => 'required|max:255',
]);
$mws = new mwsController();
$result = $mws->checkCredentials($store);
if ($result) {
//credentials OK, Force Fill in database
//OK with it
// ALSO, I want to disable future Form Edits, any idea?
}else{
//return error on form, saying Merchant ID and Auth Token pair is invalid
//stuck at this point
//documentation doesnt help
}
1: Problem 1:
How can I return custom error as I commented in Code
2: I want to disable future edits in Form If Credentials Ok
Explanation
Once I have validated credentials, and updated it Database, I want that user can see the form, but he can not edit Auth Token , Merchant ID or any other field in the form.
Any guide line and help is highly appreciated
thanks
I would keep your validation in the validate method. That way your error response will work out of the box. How to extend the validator is explained here: https://laravel.com/docs/5.0/validation#custom-validation-rules
It could look something like this:
Validator::extend('mwsToken', function($attribute, $value, $parameters)
{
// check if the token is valid an return result
});
And then you can just use it in your controller:
$this->validate($request, [
'name' => 'required|max:255',
'merchantId' => 'required|max:255',
'authToken' => 'required|max:255|mwsToken',
'marketplaceId' => 'required|max:255',
]);
No need for the if/else anymore. You can just assume the token is valid there, since validation already passed. And error reporting will work automatically if you set up your Validator correctly.
As for the second question, not really sure what you mean. If you do not want to allow edits in certain cases, just don't render the form. Something like this perhaps (in your controller):
public function getEdit($id) {
$model = Model::findOrFail($id);
if ($model ->hasPropertyThatMeansNoEdit()) {
abort(403);
}
// build and render edit form
}
Don't forget to do something similar in your post handler. Always assume the user is malicious. It isn't because there is no form, that a POST request can't be made, ie. by manipulating the request of a different model.
One last side note on your architecture. I noticed in your snippet you are calling your controllers directly (StoreController, mwsController). I don't think you should be doing that. Controllers are there to handle your requests, and nothing else. If you have reusable blocks of code in them, consider moving that code to a Service or a Command, and calling that command from inside your controller. It will make your controllers a lot cleaner (SRP) and makes it easier to reuse those Commands later in ie. an API or a Queue Job or something like that.
The answer to your first question is pointed out in the docs: simply add a message bag to the response. Also check out the beginner tutorial video's (by Jeffrey Wade) on Laracast, they are really helpful. The code would be:
public function store(Request $request, $id)
{
// ...
$this->validate($request, [
'name' => 'required|string|max:255',
'merchantId' => 'required|integer|max:255',
'authToken' => 'required|string|max:255',
'marketplaceId' => 'required|integer|max:255',
]);
$mws = new mwsController();
if ($mws->checkCredentials($store)) {
// Your code here
return redirect('home')->with(['success' => 'Everything OK']); // Flash session
}
return redirect('home')->withErrors(['Merchant ID and Auth Token pair is invalid']); // Error bag
}
And to display:
#if (session('success'))
<div class="positive message">{{ session('success') }}</div>
#endif
#if (count($errors) > 0)
<div class="negative message">{{ $errors->first() }}</div>
#endif
You're second question is pretty hard to answer since you've given no code or example to work with. Maybe I'm not understanding the question, but I think you are looking for middleware.
Edit: To answer the second question, add a column named 'validated' (default 0) in your database table. If the credentials are OK, update that column and set it to 1. Use that variable in your template to manipulate the form fields, for instance:
<input type="text" name="merchantId" {{ $validated ? '' : 'disabled' }}/>
In my Laravel 5.2 app, I have the following validation rules to check a field:
$rules = array(
'file' => 'mimes:jpg,png,pdf,doc,docx',
'file' => 'validate_file'
);
Now, the validate_file is a custom validation rule. I want to run it only only if the first mimes validation passes.
I know I could simply validate/redirect with errors - in two batches, first the mimes, then the validate_file, but it seems like an overkill.
Any way I can do it the smart way in Laravel 5.2?
Use "bail" attribute. It will stop validation after first failure.
$this->validate($request, [
'title' => 'bail|mimes:jpg,png,pdf,doc,docx|validate_file',
]);
https://laravel.com/docs/5.2/validation#validation-quickstart search for "bail"
Here's the code from my AuthController:
public function postRegister(Request $request)
{
$this->validate($request, [
'name' => 'required|min:3',
'email' => 'required|email|unique:users',
'password' => 'required|min:5|max:15',
]);
}
If the validation fails I'm getting redirected to the previous page. Is there a way to pass additional data along with the input and the errors (which are handled by the trait)?
Edit: Actually, the trait does exactly what I want, except the additional data I want to pass. As #CDF suggested in the answers I should modify the buildFailedValidationResponse method which is protected.
Should I create a new custom trait, which will have the same functionality as the ValidatesRequests trait (that comes with Laravel) and edit the buildFailedValidationResponse method to accept one more argument or traits can be easily modified following another approach (if any exists)?
Sure you can, check the example in the documentation:
http://laravel.com/docs/5.1/validation#other-validation-approaches1
Using the fails(); method, you can flash the errors and inputs values in the session and get them back with after redirect. To pass other datas just flash them with the with(); method.
if ($validator->fails()) {
return back()->withErrors($validator)
->withInput()
->with($foo);
}