How to use Custom and Default Validation Together? - php

I have custom validation for validating data. The custom validation doesn't have unique rule as I need to ignore this on update, therefore I am using unique rule on store() method. But this is ignored, and it only works if I change the custom validation with default validation.
It works if I have the following:
public function store(Request $request)
{
if (!$this->user instanceof Employee) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$request->validate([
'name' => 'required|max:50|unique:centers'
]);
$center = Center::create($request->all());
return response()->json($center, 201);
}
But this doesn't work if I change the method signature to the following:
public function store(CustomValidation $request)
How can I use both together? I do not want to move the custom validation code inside the method as I have to repeat msyelf for update method then.

I think it will help you
use Illuminate\Contracts\Validation\Rule;
class CowbellValidationRule implements Rule
{
public function passes($attribute, $value)
{
return $value > 10;
}
public function message()
{
return ':attribute needs more cowbell!';
}
}
and
public function store()
{
// Validation message would be "song needs more cowbell!"
$this->validate(request(), [
'song' => [new CowbellValidationRule]
]);
}
or
public function store()
{
$this->validate(request(), [
'song' => [function ($attribute, $value, $fail) {
if ($value <= 10) {
$fail(':attribute needs more cowbell!');
}
}]
]);
}

Related

How to write validation rule with resource in Laravel?

I use Laravel 8 with Resource to define routes in api.php and DestroyProductRequest in my controller:
Route::resources([
'product' => ProductController::class,
]);
In the controller:
public function destroy(DestroyProductRequest $request, Product $product) {
$product->delete();
return Response::HTTP_OK;
}
In the DestroyProductRequest.php:
public function rules() {
return [
'id' => 'required|integer|exists:products,id',
];
}
Now the key is the Route::resource convert the incoming id from the url into a model. But now how can I write the correct rule in the the rules() function?
Now it sais id: ["The id field is required."] in the error response.
Any idea?
By default Laravel does not validate the route parameters.
You have add custom logic in order to work
public function rules()
{
return [
'product' => 'required|integer|exists:products,id',
];
}
protected function validationData()
{
// Add the Route parameters to you data under validation
return array_merge($this->all(),$this->route()->parameters());
}
In a normal use case, you wouldn't validate route request. Laravel would return a 404 Not Found exception. Which is a standard and appropriate response.
Since you are using the resource, the route parameter is implicit biding key (product id), So Laravel bind the passed id as product implicitly. Change your Rules code segment as following,
public function rules() {
return [
'product' => 'required|integer|exists:products,id',
];
}
public function destroy(Product $product) {
$product->delete();
return Response::HTTP_OK;
}
If you wanna add ACL
if ($user->can('destroy', $product)) {
$product->delete();
return Response::HTTP_OK;
}
use Validator for your question
use Illuminate\Support\Facades\Validator;
public function destroy(DestroyProductRequest $request, Product $product) {
$rules = [
'id' => 'required|integer|exists:products,id',
];
$messages = [
'id.required' => 'The id field is required.',
'id.integer' => 'The id field need to be integer.',
'id.exists' => 'The id field is exists.',
];
Validator::make($request->all(), $rules, $messages)->validate();
$product->delete();
return Response::HTTP_OK;
}
Read more here: https://laravel.com/docs/8.x/validation

How to create a callback in laravel validation when it failed-validated and passed-validated?

I have here a validation in my custom request file.
class AuthRequest extends FormRequest
{
public function store()
{
return $this->validate([
'first_name' => ['required','min:2','max:30',new PersonNameRule],
'last_name' => ['required','min:2','max:30',new PersonNameRule],
'username' => ['required','confirmed',new UsernameRule]
]);
}
public function rules(){ return []; }
}
In my controller, this is how use it.
public function store(AuthRequest $request)
{
$data = $request->store();
return request()->all();
}
My question is how can I do these things below:
when validation failed - create a session / session(['attempt' => session('attempt')+1 ?? 1]);
when validation passed - destroy the session / session()->forget('attempt')
#mrhn is right you did not fill the rules inside the function, so the FormRequest will always return false. What you did instead, you prefer to create your own method(s) and by using the $this->validate().
Now here's how to achieve your problem, in file ..\Illuminate\Validation\Validator.php find the validate() function, and put those session you desired to perform, like these below.
public function validate()
{
if ($this->fails()) {
session(['attempt' => session('attempt')+1 ?? 1]);
throw new ValidationException($this);
}else{
session()->forget('attempt');
}
return $this->validated();
}
The solution above is global which means it will perform everytime you use $this->validate().
You can use Validator instance instead of calling validate()
$validator = Validator::make($request->all(), [
'first_name' => ['required','min:2','max:30',new PersonNameRule],
'last_name' => ['required','min:2','max:30',new PersonNameRule],
'username' => ['required','confirmed',new UsernameRule]
]);
if ($validator->fails()) {
// create a session
} else {
// destroy the session
}
You can see more in the doc here: https://laravel.com/docs/7.x/validation#manually-creating-validators
Firstly i will convert your validation to a form request, this will automatically resolve when injected into a controller.
UserCreateRequest extends FormRequest {
public function rules() {
'first_name' => ['required','min:2','max:30',new PersonNameRule],
'last_name' => ['required','min:2','max:30',new PersonNameRule],
'username' => ['required','confirmed',new UsernameRule]
}
}
To use it inject it like so.
public create(UserCreateRequest $request) {
...
}
Here you can utilize two callback methods passedValidation() and failedValidation(), in your form request.
protected function failedValidation(Validator $validator) {
session(['attempt' => session('attempt')+1 ?? 1]);
return parent::failedValidation($validator);
}
protected function passedValidation() {
session()->forget('attempt')
return parent::passedValidation();
}

Insert record after Laravel form validation

I'm trying a Laravel 5.8 request validation. I managed to return errors and display them to my view. The problem is when I try to not trigger any validation rule, for whatever reason I cannot insert records into my table.
Error
Too few arguments to function
App\Http\Requests\FieldRequest::Illuminate\Foundation\Providers{closure}(),
0 passed and exactly 1 expected
Controller
class FormController extends Controller
{
public function create()
{
return view('create');
}
public function store(FieldRequest $req)
{
$validate_data = $req->validate();
Form::create($validate_data);
return redirect()->back()->with('message', 'Success!');
}
}
FormRequest
class FieldRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'item_name' => 'bail|required|max:255',
'sku_no' => 'required|alpha_num',
'price' => 'required|numeric',
];
}
public function messages()
{
return [
'item_name.required' => 'An Item Name is required',
'sku_no.required' => 'An SKU NO is required',
'price.required' => 'The price is required',
];
}
}
I'm expecting something to be inserted in my table. Do I need to perform the validation in my controller or not to achieve this? Thanks in advance!
public function store(FieldRequest $req)
{
$data = $req->all();
Form::create($data);
return redirect()->back()->with('message', 'Success!');
}
when you are working with form request you no need to use validate() function because your request goes in form request to validate your data then it will store records

Override Backpack validation roles

What I did:
I am trying to override backpack form validation roles (update request).
UserUpdateCrudRequest.php
use App\Http\Requests\Backpack\PermissionManager\UserUpdateCrudRequest as UpdateRequest;
class UserUpdateCrudRequest extends \Backpack\PermissionManager\app\Http\Requests\UserUpdateCrudRequest
{
function __construct()
{
parent::__construct();
}
public function authorize()
{
// only allow updates if the user is logged in
return \Auth::check();
}
public function rules()
{
$rules = [
'name' => 'required',
'password' => 'confirmed',
];
return $rules;
}
}
app/Http/Controllers/Admin/Backpack/PermissionManager/UserCrudController.php
public function update(UpdateRequest $request)
{
//code
}
What I expected to happen:
The email field is mandatory on create , and not mandatory on update.
What happened:
ErrorException in UserCrudController.php line 18:
Declaration of App\Http\Controllers\Admin\Backpack\PermissionManager\UserCrudController::update() should be compatible with Backpack\PermissionManager\app\Http\Controllers\UserCrudController::update(Backpack\PermissionManager\app\Http\Requests\UserUpdateCrudRequest $request)
If I'm right,
inside UserCrudController you have,
use Backpack\PermissionManager\app\Http\Requests\UserStoreCrudRequest as StoreRequest;
use Backpack\PermissionManager\app\Http\Requests\UserUpdateCrudRequest as UpdateRequest;
If you want to make the email field not mandatory on update you have to edit the UserUpdateCrudRequest.php inside your-project/vendor/backpack/permissionmanager/src/app/Http/Requests and remove the line
'email' => 'required',

Merge 2 rules FormFequest for validate an update and store action in laravel5.5

I have 2 FormRequest classes (ReadersFormRequest, SocialMediaFormRequest) and I want to store and update a Reader. A Reader may have 0 or many social media accounts, so it's necessary to validate the request.
ReadersFormRequest
class ReadersFormRequest extends FormRequest
{
public function rules()
{
return [
'first_name'=>'required',
'last_name'=>'required',
'birthday'=>'required',
'region'=>'required',
'photo_url'=>'required',
'support'=>'required',
'riwayas_id'=>'required',
'description'=>'required',
];
}
}
SocialMediaFormRequest
public function rules()
{
return [
'url'=>'required|url',
'title'=>'required'
];
}
So I want to merge the SocialMediaFormRequest rules in ReadersFormRequest rules
I found a solution:
make SocialMediaFormRequest rules a static method and merge it in SocialMediaFormRequest rules
SocialMediaFormRequest
public static function rules()
{
return [
'url'=>'required|url',
'title'=>'required'
];
}
ReadersFormRequest
public function rules()
{
return array_merge(SocialMediaFormRequest::rules(),[
'first_name'=>'required',
'last_name'=>'required',
'birthday'=>'required',
'region'=>'required',
'photo_url'=>'required',
'support'=>'required',
'riwayas_id'=>'required',
'description'=>'required',
]);
}
I think the merge is correctly done, but in update controller when I call this ReadersFormRequest, I don't know what happens.
public function update(ReadersFormRequest $request, Readers $reader)
{
// valid and update reader
Readers::whereId($reader->id)->update([
'first_name' => $request->validated()['first_name'],
'last_name' => $request->validated()['last_name'],
'photo_url' => $request->validated()['photo_url'],
'birthday' => $request->validated()['birthday'],
'region' => $request->validated()['region'],
'support' => $request->validated()['support'],
'riwayas_id' => $request->validated()['riwayas_id'],
'description' => $request->validated()['description']
]);
// For update their social media account links
foreach ($request->validated()['url'] as $key => $url)
{
}
return redirect(route('readers.show',$reader));
}
When I PUT the reader form this controller is not called.
Alter your class to:
class ReadersFormRequest extends FormRequest
{
public function rules()
{
return [
'first_name'=>'required',
'last_name'=>'required',
'birthday'=>'required',
'region'=>'required',
'photo_url'=>'required',
'support'=>'required',
'riwayas_id'=>'required',
'description'=>'required',
'url'=>'required|url',
'title'=>'required'
];
}
}
or if you really want to use a class do:
class ReadersFormRequest extends FormRequest
{
public function rules(SocialMediaFormRequest $social)
{
$mediaRules = $social->rules();
$rules = [
'first_name'=>'required',
'last_name'=>'required',
'birthday'=>'required',
'region'=>'required',
'photo_url'=>'required',
'support'=>'required',
'riwayas_id'=>'required',
'description'=>'required',
];
return array_merge($rules,$mediaRules);
}
}
This's how I handled it in similar situation:
public static function combineValidations($rules1, $rules2)
{
if(!is_array($rules2)) return $rules1;
foreach($rules2 as $key => $item)
{
if(!isset($rules1[$key]))
{
$rules1[$key] = $item;
}else
{
$rules1[$key] .= '|'.$item;
}
}
return $rules1;
}

Categories