How to adopt FormRequest to API JSON request? Now it looks as:
class CreateOrder extends FormRequest
{
// Validation rules
public function rules()
{
return [
'DeliveryDate' => 'required|date_format:d-m-Y H:m:s',
'PostCard' => 'boolean',
'PostCardText' => 'string|max:250',
'PhotoBefore' => 'boolean',
'Remark' => 'string|max:200',
'OrderDate' => 'required|date_format:d-m-Y',
'CallRecipientBefore' => 'boolean',
'AnonymousDelivery' => 'boolean',
'PhotoAfter' => 'boolean',
'Employers_Id' => 'required|integer',
'Employers_Id' => 'required|integer',
'Partners_Id' => 'required|integer',
];
}
public function authorize()
{
return true;
}
}
And using:
public function store(CreateOrder $request)
{
dd(Request::get('DeliveryDate'));
dd($request->all()); // Or
}
When I send data to this endpoint, Laravel instead showing incoming data $request, does redirect.
Sending data
Using Postman data is sent in raw format as:
{
"DeliveryDate": "2018-01-01"
}
As result I give Laravel screen saver.
So, I have did some tests, method is not called at all:
public function store(CreateOrder $request)
{
dd('ss');
}
Seems an error in class: CreateOrder
Related
I am making a "/bulk" endpoint for my API/REST made in Laravel 8.
My problem is that I don't know how to reuse the same FormRequest that I have for the create or update
json post to: /cars/bulk
{
"cars": [{"model": "A", "year": 2021, "plate": "AA11BB"},{"model": "B", "year": 2021, "plate": "AA12BB"},{"model": "C", "plate": "AA13BB"}]
}
// CarController.php
public function store(CarRequest $request)
{
$car = $this->carService->store($request, Car::class);
}
public function update(CarRequest $request, Car $car)
{
$this->carService->update($request, $car);
}
public function bulk(Request $request)
{
$this->carService->bulk($request);
}
// CarService.php
public function store($request, $modelClass)
{
# My code....
}
public function update($request, $model)
{
# My code....
}
public function bulk($request)
{
foreach ($request->cars AS $carData )
{
$car = Car::where('plate','=',$carData->plate)->first()
# here is the problem,
# howto validate each $car by reusing CarRequest
if ($car){
$this->update($carData, $car);
} else {
$this->store($carData, Car::class);
}
}
}
This is de form request for each item, i have use to for bulk or one request
class CarRequest extends BaseRequest
{
public function authorize()
{
$this->setModel(Car::class);
return $this->isAuthorized();
}
public function rules()
{
$this->setModel(Car::class);
$rules = parent::rules();
$rules = [
'model' => 'required',
'year' => 'required|numeric',
'plate' => 'required'
];
return $rules;
}
public function messages()
{
# multiples messages
}
}
I need reuse my request
Edit: add form request
So I wouldn't suggest using it within a loop how you have in your example, what would be better would be to create a second, bulk request that valiates an array like this.
public function rules()
{
$this->setModel(Car::class);
$rules = parent::rules();
$rules = [
'cars' => ['required', 'array'],
'cars.*.model' => 'required',
'cars.*.year' => 'required|numeric',
'cars.*.plate' => 'required'
];
return $rules;
}
You can do it with same CarRequest form request class as follows.
public function rules()
{
return[
'cars.*.model' => 'required',
'cars.*.year' => 'required',
'cars.*.plate' => 'required',
];
}
Laravel will expect that you are sending nested array. If you dont want to mix it up with CarRequest you can do it with creating another FormRequest class.
I have these request file to register a new customer, I want to be the response json when the validation fails, how can I do that?
This is the request class
<?php
namespace App\Http\Requests\Validations;
use App\Http\Requests\Request;
class RegisterCustomerRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|min:3|max:255',
'email' => 'required|email|max:255|unique:customers',
'password' => 'required|string|min:6|confirmed',
'agree' => 'required',
];
}
}
And the registration function:
public function register(RegisterCustomerRequest $request)
{
$customer = Customer::create([
'name' => $request->name,
'email' => $request->email,
'password' => $request->password,
'accepts_marketing' => $request->subscribe,
'verification_token' => Str::random(40),
'active' => 0,
]);
// Sent email address verification notich to customer
$customer->notify(new EmailVerificationNotification($customer));
$customer->generateToken();
event(new Registered($customer));
return new CustomerResource($customer);
}
in your RegisterCustomerRequest you can override default method failedValidation as below
protected function failedValidation(Validator $validator)
{
if ($this->ajax()){
throw new HttpResponseException($this->respondWithError(419,'VALIDATION_ERROR',$validator->errors()));
} else{
throw (new ValidationException($validator))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
}
also you can write your own response inside $this->ajax() like below
if ($this->ajax()){
return response()->json($validator->errors(),419);
}
I am sending some data with formData, and for one fields (object) I use: JSON.stringify(this.allValues).
and I try to validate all values from this.allValues .
Till now I tried 2 methods from here , now I try with the second one with "JsonApiMiddleware" .
But with this I validation(required) errors, even if the fields are not null.
public function rules()
{
$newValues = json_decode(request()->get('all_values')); // Here I have all values that needs to be validated
dd($newValues); // I post the respons for this below
$newValues = [
'saleforce_id' => 'required',
'customer_id' => 'required',
]
return $newValues;
}
""customer_id":49,"saleforce_id":"","lkp_invoicing_method_id":3,"lkp_product_category_id":10,"lkp_notice_period_id":5,"lkp_licence_term_id":9,"is_attrition_risk":false,"is_additional_users":false,"contract_value_exc_vat_annual":"257590...and many more
Treat the JSON object you send as a php associative array. For example let's say your sent data looks like this.
/* var allValues = */
{
data: {
requiredField1: value,
requiredField2: value,
requiredArrayField1: [
1,
2,
3,
],
optionalField1: value
}
}
Then, you can validate the data like this:
public function rules()
{
return: [
'data' => 'required|array',
'data.requiredField1' => 'required',
'data.requiredField2' => 'required',
'data.requiredArrayField1' => 'required|array',
'data.requiredArrayField1.*' => 'required|numeric',
'data.optionalField1' => 'nullable',
];
}
I found a solution.
I use the method from laracast, fureszpeter, method with middleware, and I edit it.
public function handle($request, Closure $next)
{
if ($request->has('all_values')) {
$request->merge([
'all_values' => json_decode($request->get('all_values'), true)
]);
} // only when I have all_values in my request
return $next($request);
}
}
In my existing Request:
public function rules()
{
$newValues = [
'all_values.saleforce_id' => 'required'
'all_values.customer_id' => 'required',
// and the rest of the files
]
return $newValues
}
I use the following class to validate incoming request:
class CreateInvoiceRequest extends FormRequest
{
public function authorize(Request $request)
{
return true;
}
public function messages()
{
return [
'name.required' => 'The name is required.',
'name.string' => 'The name should be a string',
'code.required' => 'Code',
'code.string' => 'Code',
'type.required' => 'Type'
];
}
public function rules()
{
return [
'name' => 'required|string',
'type' => 'string',
'code' => ['required', 'string', new InvoiceCode],
];
}
}
In fail case it returns data in {errors: "The given data was invalid."} object and http status 200.
How and where to change this status? More global question, how to handle errors and warnings in Laravel?
You can add an HTTP status to the ValidationException thrown in the failedValidation method of FormRequest:
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Validation\ValidationException;
class CreateInvoiceRequest extends FormRequest
{
// ...
protected function failedValidation(Validator $validator)
{
throw (new ValidationException($validator))
->status(500)
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
// ...
}
This is my form request code, i want to add new variable after validation success, so i can access that variable at my controller :
class CouponRequest extends Request
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'start_year' => 'required',
'start_month' => 'required',
'start_day' => 'required',
'start_time' => 'required',
'finish_year' => 'required',
'finish_month' => 'required',
'finish_day' => 'required',
'finish_time' => 'required',
];
}
public function afterValidation()
{
$this->start_date = Carbon::create( $this->start_year, $this->start_month, $this->start_day );
}
}
So after validation has no error, i can call this instance at my controller :
$request->start_date;
Could i do this?
All above methods work but in my opinion I would override the passedValidation method in the form request class. This method is called after the validation checks are passed and hence keep the data clean.
Ex.
public function passedValidation()
{
$this->merge([
'start_date' => Carbon::create( $this->start_year, $this->start_month, $this->start_day )
]);
}
If you dump the data now you should see your new start_date value as well.
You could do this
public function afterValidation()
{
$this->request->add([
'start_date' => Carbon::create($this->start_year, $this->start_month, $this->start_day)
]);
}
public function validate()
{
parent::validate();
$this->afterValidation();
}
And then access the attribute in your controller as
$request->get('start_date');
In your form request use function prepareForValidation()
protected function prepareForValidation(): void
{
$this->merge([
'start_date' => Carbon::now()
]);
}
Cheers!
I am using this method after success request for manipulations.
Source: 50116187/1101038
public function withValidator(Validator $validator)
{
if ( $validator->fails() ) {
\Log::info('Error! No Manipulation!');
}else{
$this->merge([
'custom' => 'Test Manipulation!'
]);
\Log::info('Success Manipulation!');
}
}
I made the validation in the Controller. The method has a "Request $request" parameter. I have a I do this:
$input = $request->all();
$input['my_new_field] = 'the_data';