Which data do I send wrong? - php

My incoming JSON object:
{
"date": "2018-10-10",
"fiche": 1,
"fiche_type": 2,
"description": "test",
"project_code": "444",
"invoces":
[
{
"id": 1,
"description": "Ol",
"amount": 300,
"type": "debit"
},
{
"id": 2,
"type" :"credit",
"description": "Ol2",
"amount": 200
}
]
}
Validation rules are:
public function rules()
{
return [
'date' => 'required|date_format:Y-m-d',
'fiche' => 'required|integer',
'fiche_type' => 'required|integer',
'description' => 'string',
'project_code' => 'string',
'invoices' => 'required|array',
'invoices.id' => 'required|integer',
'invoices.description' => 'string',
'invoices.amount' => 'required|numeric',
'invoices.type' => 'required|string',
];
}
I always get a common error as: Wrong data validation

If you check closely to your validation rules, specifically:
return [
// ...
'invoices' => 'required|array',
'invoices.id' => 'required|integer', // <---
'invoices.description' => 'string', // <---
'invoices.amount' => 'required|numeric', // <---
'invoices.type' => 'required|string', // <---
];
With that setup, something like this should pass the validation (at least that part):
$invoices = [
'id' => 123,
'description' => 'a description',
'amount' => 123,
'type' => 'a type',
];
but that is not what you want.. you need to actually validate an array of items (array) with that structure:
$invoices = [
[
'id' => 123,
'description' => 'a description',
'amount' => 123,
'type' => 'a type',
],
[
'id' => 345,
'description' => 'another description',
'amount' => 156,
'type' => 'another type',
],
];
So.. what is the problem?
Well, before the item keys, you need to access the key of the item itself, but given that this rules will apply for every item in the array you need to make use of a wildcard. As the documentation says:
You may also validate each element of an array. For example, to
validate that each e-mail in a given array input field is unique, you
may do the following:
$validator = Validator::make($request->all(), [
'person.*.email' => 'email|unique:users',
'person.*.first_name' => 'required_with:person.*.last_name',
]);
Likewise, you may use the * character when specifying your validation
messages in your language files, making it a breeze to use a single
validation message for array based fields:
'custom' => [
'person.*.email' => [
'unique' => 'Each person must have a unique e-mail address',
] ],
So in your case:
return [
// ...
'invoices' => 'required|array',
'invoices.*.id' => 'required|integer', // <---
'invoices.*.description' => 'string', // <---
'invoices.*.amount' => 'required|numeric', // <---
'invoices.*.type' => 'required|string', // <---
];
Check the Validation Arrays section of the documentation.

Related

How to validate an array inside an array payload in laravel

How to validate a request like for this example i want to create a custom validation for qualities based on a group type. I know how to create a custom validation for laravel but for the example below i want to create a validation for quality type based on its group type.
The payload below it just for demonstration.
$payload = [
'groups' => [
[
'type' => 'human',
'qualities' => [
[
'type' => 'hair',
'value' => 'blue'
],
[
'type' => 'height',
'value' => '188cm'
],
]
],
[
'type' => 'cat',
'qualities' => [
[
'type' => 'hair',
'value' => 'yellow'
]
]
]
]
];
You can use the wildcard, for example:
$request->validate([
'payload.*' => 'required|array',
'payload.*.type' => 'required',
'payload.*.qualities' => 'required|array',
'payload.*.qualities.*' => 'required'
]);

BadMethodCallException: Method Illuminate\Validation\Validator::validateRequired|string does not exist

I'm currently working on an API for a car dealership, small school project.
In the CarController, I'm working on the POST request for adding a car and I'm having some problems with the validation of data.
This is a sample of the kind of data I'd be receiving:
{
"model": "Q5",
"brand": "Audi",
"year": 2008,
"price": 44000,
"color": "blue",
"traction": "4x4",
"motor": {
"type": "gasoline",
"hp": 256,
"turbo": false,
"cylinders": 4,
"motor_liters": 2.0
},
"user_id": 1
}
Considering the format, I wrote the validation like this:
$request->validate([
'model' => 'required|string',
'brand' => 'required|string',
'year' => 'required|integer',
'price' => 'required|numeric',
'color' => 'required|string',
'traction' => 'required|string',
'motor' => [
'type' => 'required|string',
'hp' => 'required|integer',
'turbo' => 'required|boolean',
'cylinders' => 'required|integer',
'motor_liters' => 'required|numeric'
],
'user_id' => 'required|integer'
]);
However, when making the request, it gives me the following error from the Validator:
BadMethodCallException: Method Illuminate\Validation\Validator::validateRequired|string does not exist.
At this point I don't know if it's a typo, bad formatting or I have to handle nested JSONs differently, considering I have a UserController with a POST request that looks like this:
$request->validate([
'username' => 'required|string|min:5',
'password' => 'required|string'
]);
And it works perfectly.
If you want to try the API yourselves here's the link to the repo.
to validate nested fields you have to use dot notation and not nest arrays:
$request->validate([
'model' => 'required|string',
'brand' => 'required|string',
'year' => 'required|integer',
'price' => 'required|numeric',
'color' => 'required|string',
'traction' => 'required|string',
'motor.type' => 'required|string',
'motor.hp' => 'required|integer',
'motor.turbo' => 'required|boolean',
'motor.cylinders' => 'required|integer',
'motor.motor_liters' => 'required|numeric',
'user_id' => 'required|integer'
]);

Writing record with MeasureValues error: Please use measureValue to send the data

I am writing to Timestream a list of dimensions and a list of measureValues but I keep getting this error:
"Message":"measureValues (list) not supported for BOOL, DOUBLE, VARCHAR and BIGINT data types. Please use measureValue to send the data."
Here is my code:
$dimensions= [];
$dimensions[] = [
'Dimensions' => [
[
'DimensionValueType' => 'VARCHAR',
'Name' => 'id',
'Value' => '123456',
],
],
'MeasureValues' => [
[
'Name' => 'remark',
'Type' => 'VARCHAR',
'Value' => 'Some test text',
],
]
];
$query = [
'CommonAttributes' => [
'MeasureName' => 'table_cnt',
'MeasureValue' => 'table_cnt',
'MeasureValueType' => 'VARCHAR',
'Time' => '1651501311000',
'TimeUnit' => 'MILLISECONDS',
'Version' => 1,
],
'DatabaseName' => 'mydb',
'Records' => $dimensions,
'TableName' => 'table',
];
$db->WriteRecords($query);
According to AWS documentation here (Parameter Syntax) it clearly shows that the supported data types are "DOUBLE|BIGINT|VARCHAR|BOOLEAN|TIMESTAMP|MULTI". If you check a bit down below under "MeasureValues" bulletpoint, it says the opposite: "This is only allowed for type MULTI." . Eitherway, I did try to change the type to MULTI but it still throws the same error.
As you're expecting to use the format
[
'Name' => 'remark',
'Type' => 'VARCHAR',
'Value' => 'Some test text',
],
as input to measures, you need to declare the MeasureValueType as 'MULTI' and not send a MeasureValue on the body of the request. In your example, the final request would be like this:
$dimensions= [];
$dimensions[] = [
'Dimensions' => [
[
'DimensionValueType' => 'VARCHAR',
'Name' => 'id',
'Value' => '123456',
],
],
'MeasureValues' => [
[
'Name' => 'remark',
'Type' => 'VARCHAR',
'Value' => 'Some test text',
],
]
];
$query = [
'CommonAttributes' => [
'MeasureName' => 'table_cnt',
// Removed MeasureValue from here as it's MULTI
'MeasureValueType' => 'MULTI', // <- changed from 'VARCHAR' to 'MULTI'
'Time' => '1651501311000',
'TimeUnit' => 'MILLISECONDS',
'Version' => 1,
],
'DatabaseName' => 'mydb',
'Records' => $dimensions,
'TableName' => 'table',
];
$db->WriteRecords($query);
As a reference, I would suggest you to try it first without the CommonAttributes, as you're inserting only one record, like I demonstrate on this article: https://du7.medium.com/aws-timestream-multi-measures-71b41c089af4

Combine mongoDB $lookup with $project

Right now I'm using the $project aggregation for filtering out unnecessary fields. Also I'm using the $lookup aggregation to link two collections togethe and I know how to use both of them in the main collection.
Now my question is; how can I put this $project aggregation inside of a lookup?
What I have now is looks like this:
[
'$lookup' => [
'from' => Media::collectionName(),
'localField' => '_id',
'foreignField' => 'project_id',
'as' => 'mediaList'
]
],
[
'$project' => [
'title' => 1,
'owner_id' => 1,
'owner_name' => 1,
'created_at' => 1,
'updated_at' => 1,
'status' => 1,
'discount' => 1,
'company' => 1,
'media' => [
'$filter' => [
'input' => '$mediaList',
'as' => 'media',
'cond' => $mediaFilter
]
]
]
],
So I can filtering out the unnecessary fields in the main collection. How can I do this in the sub-collection?
If I understood your question correctly, you want to apply a $filter operation on your $mediaList field.
To avoid a redundant $project stage (where you have to declare every single field you want to keep), use $addFields stage instead, like this :
[
'$lookup' => [
'from' => Media::collectionName(),
'localField' => '_id',
'foreignField' => 'project_id',
'as' => 'media' // Note that I use the same name for the field
]
],
[
'$addFields' => [
'media' => [
'$filter' => [
'input' => '$media',
'as' => 'media',
'cond' => $mediaFilter
]
]
]
],

ZF2 how to set message of required field when it's empty?

I have an input filter...
$this->inputFilter->add($factory->createInput([
'name' => 'reason',
'required' => true,
'filters' => [
[
'name' => 'StripTags'
]
],
'validators' => [
[
'name' => 'StringLength',
'options' => [
'min' => 10,
'max' => 150
]
]
]
]));
When the length is 0, the 'required' error kicks in (appears to use NotEmpty validator.) This gives a very generic message "Value is required and can't be empty."
Since I am showing all errors in list above the form and not next to their input, this is not specific enough.
I am assuming there is a 'messages' key like in the validators array, but I cannot find any documentation on it.
How can I set the message for an empty input?
I dug through the InputFactory code and found a few things...
continue_if_empty will allow an empty field and still run the validators.
$this->inputFilter->add($factory->createInput([
'name' => 'reason',
'continue_if_empty' => true,
'filters' => [
[
'name' => 'StripTags'
]
],
'validators' => [
[
'name' => 'StringLength',
'options' => [
'min' => 10,
'max' => 150,
'messages' => [
\Zend\Validator\StringLength::TOO_SHORT => 'The reason must be greater than %min% characters.',
\Zend\Validator\StringLength::TOO_LONG => 'The reason must be less than %max% characters.'
]
]
]
]
]));
You could also add the error_message config. It appears it will always show this error and no others regardless of what happens. This is fine since the only validator is StringLength.
$this->inputFilter->add($factory->createInput([
'name' => 'reason',
'error_message' => 'The reason must be between 10 and 150 characters in length.',
'filters' => [
[
'name' => 'StripTags'
]
],
'validators' => [
[
'name' => 'StringLength',
'options' => [
'min' => 10,
'max' => 150,
]
]
]
]));
If you still require a "not empty" message, you should be able to add a NotEmpty validator, customize its message, and use continue_if_empty => true config.

Categories