I have an array that makes in front end with js and pass that to my controller with ajax.
Ajax:
var values = [{FirstName: "fff"},{LastName: null}]
$.ajax({
method: "POST",
url: "/api/store-step",
data: { values: values, step: activePanelNum }
}).fail(function (jqXHR, textStatus, error,result) {
console.log(jqXHR.responseJSON.errors);
}).done(function( result ) {
console.log(result);
});
structure of array is this:
[{FirstName: "fff"},{LastName: null}]
Controller:
public function storeSteps(Request $request)
{
$validator = Validator::make($request->values, [
'FirstName' => 'required',
'LastName' => 'required',
]);
if ($validator->fails()) {
return response()->json(['success'=>false, 'errors' => $validator->getMessageBag()->toArray()],422);
}
}
I can't validate this array with request validation Laravel. Now I'm going to turn this array into a Larval request to apply the rules to it.
Can any one helps?
you can validate array element like this
$validator = Validator::make($request->all(), [
'values' => 'required',
'values.*.FirstName' => 'required',
'values.*.lastName' => 'required','
]);
by using . you can access an index in a array and * apples all indexes in the array.
Related
I want to add product to my session array but always it overwriting existing product and is only one.
/**
* #Route("/{id}", name="add", methods={"GET"})
*/
public function add(Product $product, Request $request): Response
{
$session= $request->getSession();
$session->set('products', array(
'list' => $product,
));
$this->addFlash('success', 'add');
return $this->render('index.html.twig', [
'product' => $product
]);
}
any suggestion?
You overwrite the session variable each time instead of adding a new product. Try to get the product, add new product, then set the session:
public function add(Product $product, Request $request): Response
{
$session= $request->getSession();
$products = $session->get('products', []);
$session->set('products', array(
'list' => array_merge($products['list'] ?? [], [$product])
));
$this->addFlash('success', 'add');
return $this->render('index.html.twig', [
'product' => $product
]);
}
If you want to have distinct products you may use product['id'] as the key
public function add(Product $product, Request $request): Response
{
$session= $request->getSession();
$products = $session->get('products', []);
$products[$product['id']] = $product;
$session->set('products', products);
$this->addFlash('success', 'add');
return $this->render('index.html.twig', [
'product' => $product
]);
}
I have this request:
GET http://example.com/test?q[]=1&q[]=2&q[]=3
And I have this route:
Route::get('test', function(Request $req) {
$req->validate(['q' => 'array']);
});
How should I do to add other validation rules to each element of this array using Laravel validator? For example, I want to check that each q value has a minimum of 2.
Thank you for your help.
Take a look at the documentation about validating arrays.
$validator = Validator::make($request->all(), [
'person.*.email' => 'email|unique:users',
'person.*.first_name' => 'required_with:person.*.last_name',
]);
You can also do this in your controller using the Request object, documentation about validation logic.
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// The blog post is valid...
}
There is a third option for when you have a lot of validation rules and want to separate the logic in your application. Take a look at Form Requests
1) Create a Form Request Class
php artisan make:request StoreBlogPost
2) Add Rules to the Class, created at the app/Http/Requestsdirectory.
public function rules()
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
];
}
3) Retrieve the request in your controller, it's already validated.
public function store(StoreBlogPost $request)
{
// The incoming request is valid...
// Retrieve the validated input data...
$validated = $request->validated();
}
You can do:
Route::get('test', function(Request $req) {
$req->validate([
'q' => 'array',
'q.*' => 'min:2'
]);
});
For more information on validation of arrays, see => laravel.com/docs/5.6/validation#validating-arrays
Suppose I got an array of users
users: [
{
"id": 1,
"name": "Jack",
},
{
"id": 2,
"name": "Jon"
}
]
I would validate it like below :
$request->validate([
'users[*]'=> [
"id" => ["integer", "required"],
"name" => ["string", "required"]
]
]);
Here * acts as a placeholder
Take this request data:
HTTP PUT
[
'id' => 1,
'company' => 'Company Name',
'attributes' => [
[
'attribute' => 'url',
'value' => 'example1.com'
],
[
'attribute' => 'url',
'value' => 'example2.com'
],
]
]
I want to build a form that validates attributes using choice loaders:
public function buildForm(FormBuilderInterface $builder, array $options): void
{
parent::buildForm($builder, $options);
$builder->add(
$builder->create('attributes', FormType::class, [
'compound' => true
])
);
$builder->get('attributes')
->add('attribute', ChoiceType::class, [
'constraints' => [
new NotBlank([
'message' => 'attribute name cannot be blank.'
])
],
'choices' => [
'url',
'type',
'email',
'date',
],
])
->add('value', TextType::class)
;
}
However when i write my unit test for this:
public function testAttributesForm(array $data)
{
$form = $this->factory->create(AttributesType::class);
$form->submit($data);
if(!$form->isValid()) {
var_dump($form->getErrors()->current()->getMessage());
}
}
I get a failed validation:
string(42) "This form should not contain extra fields."
Which is because it finds a nested array instead of the actual fields.
How do I pass nested data in a way where I can fully use validation constraints?
In the past I used CollectionType::class with 'allow_add' => true but it doesn't allow for very detailed validation.
You should try use directive
'allow_extra_fields' => true
To be able to validate nested data without a data_class using Forms (as you may when writing an api) you need to add a form per collection dynamically, in this case:
The first form builder method would look like this:
class CompanyType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('id', IntegerType::class)
->add('company', TextType::class)
;
$builder->add(
$builder->create('companyAttributes', CollectionType::class, [
'allow_extra_fields' => true
])
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'csrf_protection' => false,
]);
}
}
and the second would also be a standalone form:
class CompanyAttributeType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('value',TextType::class)
->add('attribute',TextType::class, [
'constraints' => [
new NotBlank([
'message' => 'Parameter name cannot be blank.'
])
],
])
;
}
}
When the request is sent, you would create the first and add the second form in a loop.
Notice the loop's $key is used for the form name so you can do $form->get(1) etc.
$form = $this->factory->create(CompanyType::class);
if(!empty($data['attributes'])) {
foreach ($data['attributes'] as $key => $parameters) {
$form->get('companyAttributes')->add($key, CompanyAttributeType::class);
}
}
$form->submit($data);
if($form->isSubmitted() && $form->isValid()) {
//2xx response
} else {
//4xx/5xx response
}
This setup will validate all forms when $form->submit($data) is called.
I need to post an array of data with the index number of the line. (If I send without the index in brackets, only the last item is being picked up by the server)
Problem is that js doesn't allow me to use brackets in the key name...
I tried to build a string with all the array data as key[0] : 'value' and than passed it in as one of the param, but that didn't work either.
Meteor.methods({
submit_order: function(){
var test = HTTP.call("POST", "https://example.com/api/",
{
headers:
{
"Content-Type": "application/x-www-form-urlencoded"
}
,
data : {ApiLogin:'login',
ApiKey:'key',
OrderNumber:'ReactTest1',
Items[0][ProductQty] : '1', <--- problem is here
Items[1][ProductQty] : '2'
},
},
function (error, result) {
if (!error) {
console.log(result);
} else{
console.log("http post error");
};
});
}
});
In PHP its written as follows:
'Items' => array(
1 => array(
'ProductQty' => 2,
),
2 => array(
'ProductQty' => 1,
),
3 => array(
'ProductQty' => 1,
)
),
You are close, you just need to set up the array in the following way:
{
ApiLogin:'login',
ApiKey:'key',
OrderNumber:'ReactTest1',
Items:[{ProductQty : '1'},{ProductQty : '2'}]
}
I know this has been asked a lot, but I can't seem to find the error.
To start things off, is there any possibility I can laravel let display an more specefic error than 500 Internal Server? Because I just assume I pass in wrong data now, but I can't be sure ...
The data I post:
Vertrekpuntvallt=50.93766174471314&Vertrekpuntvallng=3.8891601562499996&Eindpuntvallt=51.07246834624617
&Eindpuntvallng=3.592529296875&name=blablabla&description=beschrijvint+blabla&ridedate=Sat+Oct+10+2015
+00%3A00%3A00+GMT%2B0200+(CEST)&ridetime=Thu+Jan+01+1970+11%3A11%3A11+GMT%2B0100+(CET)&ridepersons=3
&ridevertrekpunt=Svhool&rideeindpunt=Dinge
My Submitfunction (not returning specefic error):
$scope.submitRide = function() {
Ride.save($scope.rideData)
.success(function (data) {
console.log("Da hebe hij goed gedaan jong!");
})
.error(function(error) {
console.log("nope");
console.log(error);
});
};
My Controller:
public function store(StoreRideRequest $request)
{
$todo = Ride::create($request->all());
return $todo;
}
My SoreRideRequest Rules:
public function rules()
{
return [
'name' => 'required',
'description' => 'required',
'ridedate' => 'date',
//Update: 'ridetime' => 'time' is not possible!! Still not fixed though :D
//'ridetime' => 'time',
'ridepersons' => 'required',
'ridevertrekpunt' => 'required',
'rideeindpunt' => 'required',
'Vertrekpuntvallt' => 'required',
'Vertrekpuntvallng' => 'required',
'Eindpuntvallt' => 'required',
'Eindpuntvallng' => 'required'
];
}
And finally my model:
protected $fillable = [
'name',
'description',
'ridedate',
'ridetime',
'ridepersons',
'ridevertrekpunt',
'rideeindpunt',
'Vertrekpuntvallt',
'Vertrekpuntvallng',
'Eindpuntvallt',
'Eindpuntvallng'
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
];
protected $dates = [
'ridedate'
];
public function user()
{
return $this->belongsTo(User::class);
}
Update: I will also post a portion of my db:
// Data
$table->string('name');
$table->text('description');
$table->date('ridedate');
$table->time('ridetime');
$table->tinyInteger('ridepersons');
$table->string('ridevertrekpunt');
$table->string('rideeindpunt');
$table->float('Vertrekpuntvallt');
$table->float('Vertrekpuntvallng');
$table->float('Eindpuntvallt');
$table->float('Eindpuntvallng');
// Foreign Keys
$table->integer(CreateRidesTable::FK)
->unsigned();
$table->foreign(CreateRidesTable::FK)
->references(CreateRidesTable::PK)
->on(CreateUsersTable::TABLE)
->onDelete('cascade');
I know there is some wrong data here? But I can't seem to figure it out.