I am using latest Laravel version.
I have requests/StoreUser.php:
public function rules() {
return [
'name' => 'required||max:255|min:2',
'email' => 'required|unique:users|email',
'password' => 'required|max:255|min:6|confirmed'
];
}
for creating a user.
Now I need and to update the user, but how can I execute only specific rules ?
For the example, if name is not provided, but only the email, how can I run the validation only for the email ?
This is easier than you thought. Make rules depend on the HTTP method. Here is my working example.
public function rules() {
// rules for updating record
if ($this->method() == 'PATCH') {
return [
'name' => 'nullable||max:255|min:2', // either nullable or remove this line is ok
'email' => 'required|unique:users|email',
];
} else {
// rules for creating record
return [
'name' => 'required||max:255|min:2',
'email' => 'required|unique:users|email',
'password' => 'required|max:255|min:6|confirmed'
];
}
}
You can separate your StoreUser request to CreateUserRequest and UpdateUserRequest to apply different validation rules. I think, this separation makes your code more readable and understandable.
Any HttpValidation request in laravel extends FormRequest that extends Request so you always have the ability to check request, auth, session, etc ...
So you can inside rules function check request type
class AnyRequest extends FormRequest
{
public function rules()
{
if ($this->method() == 'PUT'){
return [
]
}
if ($this->method() == 'PATH') {
return [
]
}
}
}
If things get complicated you can create a dedicated new HttpValidation request PostRequest PatchRequest
class UserController extends Controller
{
public function create(CreateRequest $request)
{
}
public function update(UpdateRequest $request)
{
}
}
See also the Laravel docs:
https://laravel.com/docs/5.8/validation
https://laravel.com/api/5.8/Illuminate/Foundation/Http/FormRequest.html
Related
I use 2 customs requests, one for the register, and one for the password change.
In both, there is the same password validation. How can I avoid duplicating this code and have it in only one request?
I don't know if it is possible, I would like to have your opinion.
Kylian
You can create your own CustomRequest class to validate your requests in Laravel.
Class CustomRequest extends Request
{
public function rules()
{
return [
'password' => 'required',
'username' => 'required'
];
}
public function messages()
{
return [];
}
}
use this above class in controller function.
public function functionName(CustomRequest $customRqt)
{
try {
dd($customRqt->all());
} catch (\Throwable $th) {
$thow $th;
}
}
this will help you to avoid duplicacy. I haven't run this code, but this will give you an idea.
Is it possible to use 2 different FormRequest validations in a single Controller, one for store and the other for index, how?
I used method() to returns different validations from rules(), ex:
public function rules()
{
if($this->method() == 'GET')
{
return [
'customer' => 'required|numeric',
];
}
if($this->method() == 'POST')
{
return [
'author' => 'required|numeric',
];
}
}
but looks very uncomfortable
You can use 2 different Formrequest in one controller.
I do it as following
class PostController extends Controller
{
public function index(ManagePostRequest $request){
// your code goes here
}
public function create(CreatePostRequest $request){
// your code goes here
}
public function store(StorePostRequest $request){
// your code goes here
}
}
So according to the method you can have different rules in form request. Also you can use them for authorize the method.
Hope this is what you were asking as the question was a little unclear to me.
Can I set a default value to a not-existing field in a FormRequest in Laravel?
For example, if a field called "timezone" does not exist in the incoming request, it get set to "America/Toronto".
Well I wrote a trait for this, which checks a function called 'defaults' exist in the form request it will replace the default values
trait RequestDefaultValuesTrait {
protected function prepareForValidation(){
// add default values
if( method_exists( $this, 'defaults' ) ) {
foreach ($this->defaults() as $key => $defaultValue) {
if (!$this->has($key)) $this->merge([$key => $defaultValue]);
}
}
}
}
the thing that you need to do is adding this trait to FormRequest class and then add a function like this:
protected function defaults()
{
return [
'country' => 'US',
'language' => 'en',
'timezone' => 'America/Toronto',
];
}
Being honest I don't link this method, but It works.
Try this
if(!$request->has('timezone') {
$request->merge(['timezone' =>'America/Toronto']);
}
I'm not so sure if you need to do it in this way, but if you want to:
class CreateUpdateDataFormRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
protected function getValidatorInstance()
{
$data = $this->all();
if(!isset($data['timezone'])) {
$data['timezone'] = 'America/Toronto';
$this->getInputSource()->replace($data);
}
// modify data before sending to validator
return parent::getValidatorInstance();
}
in request class add
public function prepareForValidation()
{
$this->mergeIfMissing([
'timezone' => 'America/Toronto'
]);
}
I have an endpoint for data create.
The request is "name". I need to generate "slug" and validate that slug is unique.
So, let's say
book_genres table.
id | name | slug
Request is ["name" => "My first genre"].
I have a custom request with a rule:
"name" => "string|unique:book_genres,name".
I need the same check for the slug.
$slug = str_slug($name);
How can I add this validation to my custom request?
Custom request class:
class BookGenreCreate extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
"name" => 'required|string|unique:book_genres,name',
];
}
}
So basically what you want to do is try to manipulate the request data before validation occurs. You can do this in your FormRequest class by overriding one of the methods that is called before validation occurs. I've found that this works best by overriding getValidatorInstance. You can then grab the existing data, add your slug to it and then replace the data within the request, all before validation occurs:
protected function getValidatorInstance()
{
$data = $this->all();
$data['slug'] = str_slug($data['name']);
$this->getInputSource()->replace($data);
return parent::getValidatorInstance();
}
You can also add the rules for your slug to your rules method as well:
public function rules()
{
return [
"name" => 'required|string|unique:book_genres,name',
"slug" => 'required|string|unique:book_genres,slug',
];
}
So your class will look something like this:
class BookGenreCreate extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|unique:book_genres,name',
'slug' => 'required|string|unique:book_genres,slug',
];
}
protected function getValidatorInstance()
{
$data = $this->all();
$data['slug'] = str_slug($data['name']);
$this->getInputSource()->replace($data);
return parent::getValidatorInstance();
}
}
Now when the request comes through to your controller, it will have been validated and you can access the slug from the request object:
class YourController extends Controller
{
public function store(BookGenreCreate $request)
{
$slug = $request->input('slug');
// ...
}
}
You can add the 'slug' to the request, then use validations as usual.
rules() {
// set new property 'slug' to the request object.
$this->request->set('slug', str_slug($request->name));
// rules
return [
'name' => 'string|unique:book_genres,name',
'slug' => 'string|unique:book_genres,slug'
]
}
in my laravel 5.1 app, I've got a Book model with a required "Title" field and several others non-required fields. To validate Book create/update, I use form request validation like this:
class StoreBookRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'title' => 'required',
'year' => 'numeric',
'pages' => 'numeric',
];
}
}
I then type-hint the request on the controller action and everytning works fine. Now I need to create a new controller action that updates only one of the non-required fields. To do so, I created another request like this:
class StoreReviewRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'vote' => 'numeric',
];
}
}
and I type-hint the request in the controller action:
public function updateReview(StoreReviewRequest $request, Book $book)
{
$input = array_except(Input::all(), '_method');
$book->update($input);
Session::flash('message', 'Review updated');
return redirect('/book');
}
The problem is that when I use the new controller action, the update form does not pass validation, but complains about missing "Title" field, even tough I'm not decalring that field as required in my StoreReviewRequest class. What am I doing wrong? Thanks!
As #Needpoule suggested, I was using the wrong action in my form.