I'm trying to validate a json I'm getting via post, using the Dingo API library in Laravel. It seems that the validation is working incorrectly as I send a valid JSON according to the fields I am validating and it returns me the message saying:
The X field is required.
But I'm sending the X field in json, which I do not understand.
JSON:
[
{
"currency_id": 1,
"bills": [
{
"barcode": "99999.9999999.99999999.9999 9",
"due_date": "2018-09-14",
"value": 70.00
},
{
"barcode": "8888.888888.88888.8888 8",
"due_date": "2018-09-15",
"value": 32.00
}
]
}
]
I'm getting this error:
"message": "422 Unprocessable Entity",
"errors": {
"currency_id": [
"The currency id field is required."
],
"bills": [
"The bills field is required."
]
},
This is my custom FormRequest with validation rules, where I pass it as a parameter in the BillController store method.
namespace App\Http\Requests;
use App\Rules\Sum;
use Dingo\Api\Http\FormRequest;
class BillRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'currency_id' => 'required|integer|exists:currency,id',
'bills' => ['required', 'array', 'min:1', 'max:3', new Sum],
'bills.*.barcode' => 'required|string|min:10|max:255',
'bills.*.due_date' => 'date',
'bills.*.value' => 'required|numeric|between:10,30000',
];
}
}
To solve I had to put *. in front of each rule, as I'm getting an array the validator only understands this way.
public function rules()
{
return [
'*.currency_id' => 'required|integer|exists:currency,id',
'*.bills' => ['required', 'array', 'min:1', 'max:3', new Sum],
'*.bills.*.barcode' => 'required|string|min:10|max:255',
'*.bills.*.due_date' => 'date',
'*.bills.*.value' => 'required|numeric|between:10,30000',
];
}
Related
I am working on returning validation errors in multiple languages at the same time.
I have a controller that injects a class that extends FormRequest and I am overriding 'failedValidation' and there I get the validator error messages.
public function store(SysUserStoreRequest $request)
{
// ...
}
class SystemUserStoreRequest extends ApiRequest
{
// This extends another class ApiRequest
Here I defined rules()
}
class APIRequest extends FormRequest
{
// Here I override the FailedValidation method.
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException($this->response($validator->getMessageBag()->toArray()));
}
}
The above code currently returns the error in the default language.
I can change the response to show in a different language by changing the locale in the middleware, but I am working on requirement where I need to return a new structure of validation error with each field errors in both en and fr.
I need the structure like below:
{
"detail": {
"email": {
"en-CA" : [
"The email has already been taken."
],
"fr-CA" : [
"The french text."
]
},
"first_name": {
"en-CA" : [
"The first name must be at least 5.",
"The first name must be an integer."
],
"fr-CA" : [
"The french text",
"The french text."
]
}
}
}
So i tired to override the failedValidation method and do something like below:
$validation_structure = [];
if ($validator->fails()) {
$failedRules = $validator->failed();
}
after getting the al the failed rules i can then get the string from the lang folder for each locale and get the string for the field and rule and generate the message using
$x[] = __('validation.unique', [], 'fr-CA');
$x[] = __('validation.unique', [], 'en-CA');
this will give me the string in both labguages but I do not know how to replace the :attributes, :values and various other string replacements.
You could overwrite the message bag the SystemUserStoreRequest will give back to format the messsages.
class SystemUserStoreRequest extends ApiRequest
{
public function rules()
{
return [
'email' => 'required|unique:users,email,' . $this->id,
];
}
public function messages()
{
return [
'email.required' => [
'nl' => __('validation.required', ['attribute' => __('portal.email', [],'nl')], 'nl'),
'en' => __('validation.required', ['attribute' => __('portal.email', [],'en')], 'en'),
],
'email.unique' => [
'nl' => __('validation.unique', ['attribute' => __('portal.email', [],'nl')], 'nl'),
'en' => __('validation.unique', ['attribute' => __('portal.email', [],'en')], 'en'),
]
];
}
}
Then the output would look like:
{
"message":"The given data was invalid.",
"errors":{
"email":[
{
"nl":"E-mailadres is verplicht.",
"en":"The email field is required."
}
]
}
}
Here is some more documentation about custom messages:
https://laravel.com/docs/8.x/validation#specifying-custom-messages-in-language-files
I am building a component-driven API for a basic page-builder system and have hit a stumbling block when it comes to validation.
First, I want to explain the use-case.
if we have a component (for example in Vue) in /components/ProfileCard.vue
<script>
export default {
props: {
name: String,
age: Number,
avatar: String
}
}
</script>
I am creating a component in the backend components.php config:
<?php
return [
'profile' => [
'component' => 'ProfileCard',
'rules' => [
'name' => [
'required',
],
'age' => [
'required',
'number',
],
'avatar' => [
'required',
]
],
],
];
Which checks and validates every time a profile card component is submitted.
Creating a custom validation rule for Component, I am able to say "the ProfileCard component is not valid" but I am not able to merge / nest the validation rules:
Component.php
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\Validator;
class Component implements Rule
{
protected $validator = null;
public function passes($attribute, $value)
{
$components = config('components');
$component = $value['component'];
if (isset($components[$component])) {
return false;
}
$c = $components[$component];
$this->validator = Validator::make($value['data'], $c['rules'], $c['messages'] ?? '');
return $this->validator->passes();
}
public function message()
{
if (is_null($this->validator)) {
return 'The component does not exist';
}
return $this->validator->errors();
}
}
Has anybody got any experience doing anything like this or can anybody point me in the right direction towards a solution?
I am ideally looking for a solution which is applicable while using Laravel's FormRequest validation, like so:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Unique;
use App\Rules\Component;
class CreateUserRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'email' => [
'required',
'email',
new Unique('users', 'email'),
],
'profile' => [
'required',
new Component(),
]
];
}
}
The data would come in like so:
{
"email": "test#example.com",
"profile": {
"component": "ProfileCard",
"data": {
"name": "Test",
"age": 49,
"avatar": "https://example.com/avatar.png"
}
}
}
I have updated the question with the progress I have made myself, you can return a MessageBag in the messages method on the rule, however, this creates a slight problem, the response comes back as follows:
"message": "The given data was invalid.",
"errors": {
"profile": [
{
"name": [
"The name field is required."
],
"age": [
"The age field is required."
],
"avatar": [
"The avatar field is required."
],
},
":message"
]
}
Clearly this is an improvement but it's still not as usable, we don't have a ':message' and the validation errors are nested in an object in the "profile" array.
Your approach seems like you are over complicating a simple problem. I would never do a validation in a validation rule. Instead do rules that is dependent on the component and adjust it in the form request accordingly. You can easily do nested rules like so.
[
'profile.name' => 'string',
]
Do the rest of the logic in the form request. The strategy is to have rules based on the request input and your config file, based on what you already tried.
public function rules()
{
// i do not know how you determine this key
$componentKey = 'profile';
$rules = [
...,
$componentKey => [
'required',
]
];
$inputComponent= $this->input('profile')['component'];
$components = config('components');
// based on your data this seems wrong, but basically fetch the correct config entry
$component = $components[$inputComponent];
foreach ($component['rules'] as $key => $value) {
$rules[$componentKey . '.' . $key] => $value;
}
return $rules;
}
There is some parts of your code where i can't figure out what your data means, i do not know how you get the component key profile and your code based on the config and the component field seems wrong and should instead do a loop with a where condition. I think that this can get you in the right direction, this solution will solve your message problem and be way simpler.
I am creating a laravel multiple array of an object API but my controller gives an error
Below is the request
[
{
"ProductTitle": "Clarks Men's Tilden Cap Oxford shoe",
"ProductColor": "Dark tan leather",
"ProductImage": "imageurl"
}
,
{
"ProductTitle": "Clarks Men's Tilden Cap Oxford shoe",
"ProductColor": "Dark tan leather",
"ProductImage": "imageurl"
}
]
My API store controller is as below
public function store(Request $request)
{
$input = $request;
$validator = Validator::make($input, [
'ProductTitle' => 'required',
'ProductColor' => 'required',
'ProductImage' => 'required'
]);
if($validator->fails()){
return $this->sendError('Validation Error.', $validator->errors());
}
$cartdetails=shopCartDetails::create($request->all());
return $this->sendResponse( $cartdetails,'Great success! cart details posted');
}
Am getting error
Argument 1 passed to Illuminate\Validation\Factory::make() must be
of the type array, object given,
the results have now changed to
{
"success": false,
"message": "Validation Error.",
"data": {
"ProductTitle": [
"The product title field is required."
],
"ProductColor": [
"The product color field is required."
],
"ProductImage": [
"The product image field is required."
]
} }
seems it gets only one array
You are passing the full request object instead of the values to your validator
Validator::make($request->all()...
You can validate arrays (of objects) using * like this
$validator = Validator::make($request->all(), [
'*.ProductTitle' => 'required',
'*.ProductColor' => 'required',
'*.ProductImage' => 'required'
]);
To initialize my app I have the following route:
/initialize
This returns Taxonomies, Enumerables and a couple of other taxonomy like collections. This saves multiple HTTP requests.
Although with Dingo / Fractal, I cannot see how I can respond with multiple collections?
e.g.
return [
'taxonomies' => $this->response->collection($taxonomies, new TaxonomyTransformer);
'enumerables' => $this->response->collection($enumerables, new EnumerableTransformer);
'otherStuff' => $this->response->collection($otherStuff, new OtherStuffTransformer);
];
return response()->json([
'data' => [
'taxonomies' => $this->fractal->collection($taxonomies, new TaxonomyTransformer);
'enumerables' => $this->fractal->collection($enumerables, new EnumerableTransformer);
'otherStuff' => $this->fractal->collection($otherStuff, new OtherStuffTransformer);
]
], 200);
This should return the JSON in the format you are looking for.
I have the same issue ,and I found the solution from How to use Transformer in one to many relationship. #1054.
Here is the collection I want to return with the transfomer of dingo in my controller.
$user = User::where('email','=',$input['email'])->with('departments')->with('roles')->get();
DepartmentTransformer
class DepartmentTransformer extends TransformerAbstract
{
public function transform($department)
{
return [
'id' => $department['id'],
'name' => $department['name'],
'level' => $department['level'],
'parent_id' => $department['parent_id']
];
}
}
RolesTransformer
class RolesTransformer extends TransformerAbstract
{
public function transform($role)
{
return [
'name' => $role['name'],
'slug' => $role['slug'],
'description' => $role['description'],
'level' => $role['level']
];
}
}
UserTransformer
class UserTransformer extends TransformerAbstract
{
protected $defaultIncludes = ['departments','roles'];
public function transform($user)
{
return [
'id' => $user['id'],
'name' => $user['name'],
'email' => $user['email'],
'phone' => $user['phone'],
];
}
public function includeDepartments(User $user)
{
$dept = $user->departments;
return $this->collection($dept, new DepartmentTransformer());
}
public function includeRoles(User $user)
{
$rl = $user->roles;
return $this->collection($rl, new RolesTransformer());
}
}
In my controller
$user = User::where('email','=',$input['email'])->with('departments')->with('roles')->get();
return $this->response->collection($user, new UserTransformer());
And I got the result
"data": {
{
"id": 43,
"name": "test7",
"email": "test7#foxmail.com",
"phone": "186********",
"departments": {
"data": {
{
"id": 1,
"name": "业务一部",
"level": 1,
"parent_id": 0
}
}
},
"roles": {
"data": {
{
"name": "agent",
"slug": "agent",
"description": "业务员",
"level": 1
}
}
}
}
}
Please take note of the usage of $defaultIncludes and includeXXX() methonds in the UserTransformer.You can get more detail info from Fractal Doc.
I am sending json object with sub json object to server.I want to validate sub json object in laravel5.1 form validation method.
My object is,
{
"empType": {
"id": 2,
"title": "Part Time",
"status": 1
},
"salutation": "Mr",
"name": "Shihabuddeen",
"employee_code": "EMP1001"
}
My form validation method is,
public function rules() {
return [
'salutation' => ['required'],
'name' => ['required', 'max:100'],
'employee_code' => ['required', 'max:100'],
"empType.id" => ['required', 'integer'],
];
}
Here all other validations are working fine except "empType.id" => ['required', 'integer'].
Is there any way to do this validation?