I am using Laravel's Validation through FormRequest. An extract of the code is here. It seems laravel's validation is letting email addresses like "user#hotmail" through.
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class DirectorForm extends FormRequest
{
public function rules()
{
return [
'email' => 'required|email',
];
}
}
it seems the above validation allows "username#hotmail", which isn't a valid email address.
Did i set it up wrongly
Actually user#hotmail is a valid email, as user#localhost can also be a valid email address.
If you want to check that if the email address also contains a TLD, you can try:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class DirectorForm extends FormRequest
{
public function rules()
{
return [
'email' => 'required|regex:.+#.+\..+',
];
}
}
For more regex email validation rules take a look at this answer.
Use the regex from: https://emailregex.com/
And combine with Laravel regex rule: https://laravel.com/docs/5.8/validation#rule-regex
It appears validation is working as expected. Thanks for reading!
You can write custom validation for an email in AppServiceProvider like
Boot method
Validator::extend('email_address', function ($attribute, $value, $parameters, $validator) {
return (!preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*#([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $value)) ? FALSE : TRUE;
});
Rules
public function rules()
{
return [
'email' => 'required|email_address',
];
}
Related
I want to validate an enum in laravel, but it's not clear to me how to do this.
In my database I have an enum attribute and the migration converts the enum to an array type (e.g. enum('Delta','Statisch') -> array('Delta','Statisch')). But how do I validate the enum/ the data which I receive (how do I know which value of the enum has been selected and how can I ensure that the received value is part of the enum)?
This one is easy:
<?php
use Illuminate\Validation\Rule;
use Illuminate\Http\Request;
class DummyController extends Controller
{
public function store(Request $request)
{
$validatedData = $request->validate([
'filed_name' => ['required', Rule::in(['Delta','Statisch'])
]);
}
}
Checkout Laravel Docs for more info.
Try This
use Validator;
$validator = Validator::make([
'type' => 'in:Delta,Statisch', // DEFAULT or SOCIAL values
]);
Let's say there are two Laravel API resources Book and Author, each with some rules for validating the store request.
Then, there's a third API resource where API consumers can post a certain thing along with a Book and an Author. That is to say, the store request must accept a Book object, an Author object, and a third FooBar object:
// sample POST body
{
"book": {...book object...},
"author": {...author object...},
"foobar": {...foobar object...}
}
In the FooBarRequest validation rules(), would make sense to reuse BookRequest::rules() and AuthorRequest::rules(), but it's not working:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class FooBarRequest extends FormRequest
{
public function rules()
{
$bookRules = BookRequest::$validationRules;
$authorRules = AuthorRequest::$validationRules;
return [
'book' => $bookRules,
'authorRules' => $authorRules,
'foobar' => 'required|...some rules...'
];
}
}
Perhaps using Laravel's custom rules, but it doesn't help so much since the passes method must return a boolean (i.e. we should re-write all the validation logic for each attribute).
Is there any elegant/official way of doing this?
book and title attributes will fall under the Validating Nested Array Input rules.
For example, if you have:
$bookRules = ['title' => 'required', 'body' => 'text'];
$authorRules = ['name' => 'required'];
You want the rules to be like:
[
'book.title' => 'required',
'book.body' => 'text',
'author.name' => 'required',
'foobar' => 'required|...some rules...',
];
Assuming BookRequest::$validationRules and AuthorRequest::$validationRules already return what you want, you need to do the following to get there:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class FooBarRequest extends FormRequest
{
public function rules()
{
$bookRules = BookRequest::$validationRules;
$authorRules = AuthorRequest::$validationRules;
return array_merge(
$this->getNestedArrayRules($bookRules, 'book'),
$this->getNestedArrayRules($authorRules, 'author'),
['foobar' => 'required|...some rules...']
);
}
protected function getNestedArrayRules($rules, $key) {
return array_combine(
array_map(fn ($attribute) => "$key.$attribute", array_keys($rules)),
$rules
);
}
}
Check this answer out on Laracasts:
If you want to use the same validation rules in multiple places, perhaps use a trait and then use it in multiple form requests. So for book rules:
<?php
namespace App\Traits;
trait BookValidationTrait
{
protected function bookRules ()
{
return [
'book_input_1' => 'your rules here',
'book_input_2' => 'your rules here',
...
]
}
}
Then for author rules:
<?php
namespace App\Traits;
trait AuthorValidationTrait
{
protected function authorRules ()
{
return [
'author_input_1' => 'your rules here',
'author_input_2' => 'your rules here',
...
]
}
}
Then in your book form request class:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use App\Traits\BookValidationTrait;
class BookRequest extends FormRequest
{
use BookValidationTrait;
public function rules()
{
return $this->bookRules();
}
}
In your author form request class:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use App\Traits\AuthorValidationTrait;
class AuthorRequest extends FormRequest
{
use AuthorValidationTrait;
public function rules()
{
return $this->authorRules();
}
}
And finally, in your FooBar form request class:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use App\Traits\BookValidationTrait;
use App\Traits\AuthorValidationTrait;
class FooBarRequest extends FormRequest
{
use BookValidationTrait, AuthorValidationTrait;
public function rules()
{
return array_merge(
$this->bookRules(),
$this->authorRules(),
[
'foobar_input_1' => 'your rules here',
'foobar_input_2' => 'your rules here',
...
]
);
}
}
I haven't tested this, but it looks like that could work.
In your case, I see one way how to solve this problem, but also I'd like to demonstrate an example that can help in easier cases when you need to validate just one entity, for example, book:
Use BookRequest through DI:
class FooBarRequest extends FormRequest
{
public function rules(BookRequest $request)
{
return [
'foobar' => 'required|...some rules...'
];
}
}
Specifically for your case, I advise you to use the rules. You can use them in FooBarRequest, and also reuse them in other FormRequest classes:
class FooBarRequest extends FormRequest
{
public function rules()
{
return [
'book' => [new BookValidationRule()],
'authorRules' => [new AuthorValidationRule()],
'foobar' => 'required|...some rules...'
];
}
}
For form validation I made a Request class via php artisan make:request UpdatePlanRequest.
However after using the UpdatePlanRequest class in store the method isn't called anymore.
The UpdatePlanRequest:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdatePlanRequest 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()
{ //TODO: CHECK IF THE PROTOTYPE IDS ARE OWNED BY THE USER (https://stackoverflow.com/questions/42662579/validate-an-array-of-integers/42693970)
return [
'start_date' => 'required|date',
'end_date' => 'required|date|after:start_date',
'name' => 'required|string'
];
}
}
The controller method:
use App\Http\Requests\UpdatePlanRequest;
public function store(UpdatePlanRequest $request)
{
//
dd('hello');
}
If the function header is store(Request $request) hello is shown, in that example it isn't.
The custom Request class is necessary to call $request->validated(); later for validation purposes according to the docs.
Is there a reason you have your Request class as being abstract? The default class that is created when running php artisan make:request <name> doesn't define the class as being abstract. This seems to work for me, but not when declaring it as abstract.
$request->validated(); is used to retrieve the validated inputs, so just by calling the UpdatePlanRequest it should validate the request
//Try This
use App\Http\Requests\UpdatePlanRequest;
public function store(UpdatePlanRequest $request)
{
$validatedData = $request->validated();
dd('$validatedData');
$profile = new Profile([
'user_id' => $request->get('user_id'),
]);
$profile->save();
echo $request->session()->flash('alert-success', 'Profile details Succefully Added!');
return redirect('create')->with('success', 'Data saved!');
}
Your route will be.
Route::get('profile','ProfileController#store');
Route::post('profile/create','ProfileController#store')->name('create');
Well this works right!
When the method is called, it checks the request class (UpdatePlanRequest). If there is an error, it does not enter the method anymore and you can not see the output of dd() function.
If the data is correct after checking the rules, then dd() will be displayed.
You must manage errors
When we use Laravel Form Requests in our controllers and the validation fails then the Form Request will redirect back with the errors variable.
How can I disable the redirection and return a custom error response when the data is invalid?
I'll use form request to GET|POST|PUT requests type.
I tried the Validator class to fix my problem but I must use Form Requests.
$validator = \Validator::make($request->all(), [
'type' => "required|in:" . implode(',', $postTypes)
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()]);
}
Creating custom FormRequest class is the way to go.
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Validation\ValidationException;
use Illuminate\Http\Exceptions\HttpResponseException;
class FormRequest extends \Illuminate\Foundation\Http\FormRequest
{
protected function failedValidation(Validator $validator)
{
if ($this->expectsJson()) {
$errors = (new ValidationException($validator))->errors();
throw new HttpResponseException(
response()->json(['data' => $errors], 422)
);
}
parent::failedValidation($validator);
}
}
Class is located in app/Http/Requests directory. Tested & works in Laravel 6.x.
This is the same but written differently:
protected function failedValidation(Validator $validator)
{
$errors = (new ValidationException($validator))->errors();
throw new HttpResponseException(
response()->json([
'message' => "",
'errors' => $errors
], JsonResponse::HTTP_UNPROCESSABLE_ENTITY)
);
}
Base class FormRequest has method failedValidation. Try to override it in your FormRequest descendant
use Illuminate\Contracts\Validation\Validator;
class SomeRequest extends FormRequest
{
...
public function failedValidation(Validator $validator)
{
// do your stuff
}
}
use this on function
dont forget to take on top // use App\Http\Requests\SomeRequest;
$validatedData = $request->validated();
\App\Validator::create($validatedData);
create request php artisan make:request SomeRequest
ex.
use Illuminate\Contracts\Validation\Validator;
class SomeRequest extends FormRequest
{
public function rules()
{
return [
'health_id' => 'required',
'health' => 'required',
];
}
}
I use proengsoft/laravel-jsvalidation in combination with a custom FormRequest and custom validation rules that I defined via Validator::extend(...) in a service provider. This works well.
However, when I port my custom rules to the new(ish) custom Rule class in Laravel 5.5+, JsValidator fails at getting my custom Rule messages.
I have this custom rule:
use Illuminate\Contracts\Validation\Rule;
class MyRule implements Rule
{
public function passes($attribute, $value) {
return $value > 10;
}
public function message() {
return 'Your :attribute is pretty small, dawg!';
}
}
My form request uses this rule:
use Illuminate\Foundation\Http\FormRequest;
use App\Rules\MyRule;
class MyRequest extends FormRequest
{
public function authorize() {
return true;
}
public function rules() {
$rules = [
'foo' => 'required|numeric',
'bar' => ['required', new MyRule()],
];
return $rules;
}
}
This should work, but I get thrown an Exception on
{!! JsValidator::formRequest('\App\Http\Requests\MyRequest') !!}
An Exception is thrown from a call to Str::snake(Object(App\Rules\MyRule)) made by Proengsoft\JsValidation\Javascript\MessageParser.php.
JsValidation does not look at the $rule object type before calling Validator->getMessage($attribute, $rule)
where instead it should be calling $rule->messages();
Can I work around this bug somehow, and use laravel-jsvalidation together with my custom Rule and FormRequest -- or does it necessarily require i make a pull request and hope it will be fixed... someday? I'd like to make this work now-ish.
This can be archived by passing JsValidator instance based on rules and message arrays instead of passing the form request. In controller Pass this instance to blade. Read here for more details.
JsValidator::make($rules, $messages, $customAttributes, $selector)
In controller,
$validator = JsValidator::make(
[
'name' => 'required',
],
[
'name.required' => 'Name field is a required field',
]
)
return View::make("Your view", compact($validator));
In blade,
{!! $validator->selector('.wizard_frm') !!}
<form class='wizard_frm'></form>
And in this case we can create object of request class and pass rules function returned array to JsValidator::make if needed.