Laravel Validating An Array in Update Method unique filter - laravel

I am new to Laravel. I try to validate an array in Laravel 9.
for using a unique filter I have a problem.
at first, I try to use this way
$rules = [
'*.id' => 'integer|required',
'*.key' => 'string|unique.settings|max:255|required',
'*.value' => 'array|nullable|max:255',
];
For the Create method, this works, but for updating, the logic is wrong. I need to ignore the current field.
for the update, I try to use this way
private function update(): array
{
foreach ($this->request->all() as $keys => $values) {
// dd($values['id']);
$rules[$keys .'.id' ] = 'integer|required';
$rules[$keys .'.key'] = ['string|max:255|required', Rule::unique('settings', 'key')->ignore($values['id'])];
$rules[$keys .'.value'] = 'array|nullable|max:255';
}
// dd($rules);
return $rules;
}
I got this error
BadMethodCallException: Method Illuminate\Validation\Validator::validateString|max does not exist. in file /Users/mortezashabani/code/accounting/vendor/laravel/framework/src/Illuminate/Validation/Validator.php on line 1534
how can I validate an array in the update method in Laravel 9?
PS: without Rule::unique('settings','key')->ignore($values['id'])] all filter is works without any problem

hello you can try this code in your function
$validated = $request->validate([
'id' => 'required',
'key' => 'string|unique.settings|max:255|required',
'value' => 'array|nullable|max:255',
]);

Related

Validating form comaring two fields values

I'm trying to find Laravel 8 documentation on how to validate comparing two fields to each other. I'm creating an app that allows creating matches from teams in a database table, using the create() method in the controller. I looked into Laravel #Validation, even #Custom Validation Rules, but I can't find anything when comparing the two fields.
public function store(Request $request)
{
$validatedData = $request->validate([
'local_team' => 'required',
'local_score' => 'required|numeric',
'visitor_team' => 'required',
'visitor_score' => 'required|numeric',
]);
$score = new Score();
$score->local_team = $request->local_team;
$score->local_score = $request->local_score;
$score->visitor_team = $request->visitor_team;
$score->visitor_score = $request->visitor_score;
$score->save();
$new = true;
return redirect()->route('scores.show',
['id' => $score->id, 'new' => true]);
}
In my case, the 'local_team' and 'visitor_team' fields should be different. Any clue on how to do it?

How to validate inputs from GET request in Laravel

I wanted to validate inputs from a GET request without using the
this->validate($request... or \Validator::make($request...
and prefer to do it like
$input = $request->validate([... rules ...]);
however since get requests doesn't have $request parameters how can I achieve it?
public function sampleGet($param1, $param2) {
// How can I pass the $param1 and $param to to validate?
$input = $request->validate([
'param1' => 'required',
'param2' => 'required
]);
}
You can do so and it will have same behavior as validate
validator($request->route()->parameters(), [
'param1' => 'required',
'param2' => 'required'
....
])->validate();
If you want all the route parameters you can get them as an array:
$request->route()->parameters()
Since you already have those parameters being passed to your method you can just build an array with them:
compact('param1', 'param2');
// or
['param1' => $param1, 'param2' => $param2];
You are not going to be using the validate method on the Request though, you will have to manually create a validator. Unless you want to merge this array into the request or create a new request with these as inputs.
There is nothing special about the validate method on a Controller or on a Request. They are all making a validator and validating the data the same way you would yourself.
When manually creating a validator you still have a validate method that will throw an exception, which would be the equivalent to what is happening on Request and the Controller with their validate methods.
Laravel 7.x Docs - Validation - Manualy Creating Validators - Automatic Redirection
You can do like that.
public function getData(Request $request)
{
try {
$input['route1'] = $request->route('route1');
$input['route2'] = $request->route('route2');
$valid = Validator::make($input, [
'route1' => 'required',
'route2' => 'required'
]);
} catch (\Throwable $th) {
echo "<pre>";print_r($th->__toString());die;
}
}
Or you can follow the below link for more info.
https://laravel.com/docs/7.x/validation#manually-creating-validators

Add a custom item to eloquent collection

I am using Laravel 7.
I have Category model. I sent categories as API with laravel resources. But now I want to add "all" value to categories.
Controller:
'categories' => CategoryResource::collection(Category::all()->push([
'id' => 0,
'name' => "All",
'subcategories' => []
]))
Resource:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'subcategories' => SubcategryResource::collection($this->subcategories)
];
}
Also, I wanted to add this custom value to the beginning of the collection.
But I am getting this error:
Trying to get property 'id' of non-object
Please, help me. How can I solve my problem?
Try replacing $this->id with $this['id']
If that works your query is returning an array not an object.
The problem here is that you're trying to add an item to the collection which is not a category model. $this in the resource reverts to the given model. However, you pass in an array so there is no model.
So try this instead
$allCategory = new Category(['id' => 0, 'name' => 'All']);
'categories' => CategoryResource::collection(Category::all()->prepend($allCategory));
I got these from: https://laracasts.com/discuss/channels/eloquent/add-a-custom-value-to-eloquent-collection

How to convert object return by laravel model factory create method into array containing model fields?

For example, I have a UserFactory.php
<?php
use App\User;
use Faker\Generator as Faker;
use Illuminate\Support\Str;
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'role' => 'USER',
'password' => 'sasdcsdf34', // password
'remember_token' => Str::random(10),
];
});
Now, I can create a user as following
$user = factory(User::class)->create();
Now, How can I convert this $user object into array containing user info like name,email etc without initializing new array and manually assigning every $user object property. ??
I DON'T want to manually assign like following as it is tedious if there are many properties in $user object
$userArray=[
'id' => $user->id,
'name' => $user->name,
'email' => $user->email
]
I have tried this but it creates array containing various other properties and actual values needed are nested inside properties
$userArray=array($user)
You should try using the raw method of factory instead of create.
$user = factory(User::class)->raw();
This should give you an array you can work with.
Try to add something like this to your model class:
public function getArr(){
foreach($this->attributes as $key => $val){
$array[$key] = $val;
}
return $array;
}
If you wish to have this function in every model you could create trait with this function and then just attach it in model class or any class extending it.
You can use json_decode.
// Laravel 7
$userArray = json_decode(factory(User::class)->create(), true);
// Laravel 8
$userArray = json_decode(User::factory()->create(), true);
For Laravel 8, instead of make or create method, use:
User::factory()->raw();
This will return an array

Laravel 5.6. How to test JSON/JSONb columns

$this->assertDatabaseHas() not working with JSON/JSONb columns.
So how can I tests these types of columns in Laravel?
Currently, I have a store action. How can I perform an assertion, that a specific column with pre-defined values was saved.
Something like
['options->language', 'en']
is NOT an option, cause I have an extensive JSON with meta stuff.
How can I check the JSON in DB at once?
UPD
Now can be done like that.
I have solved it with this one-liner (adjust it to your models/fields)
$this->assertEquals($store->settings, Store::find($store->id)->settings);
Laravel 7+
Not sure how far back this solution works.
I found out the solution. Ignore some of the data label, Everything is accessible, i was just play around with my tests to figure it out.
/**
* #test
*/
public function canUpdate()
{
$authUser = UserFactory::createDefault();
$this->actingAs($authUser);
$generator = GeneratorFactory::createDefault();
$request = [
'json_field_one' => [
'array-data',
['more-data' => 'cool'],
'data' => 'some-data',
'collection' => [
['key' => 'value'],
'data' => 'some-more-data'
],
],
'json_field_two' => [],
];
$response = $this->putJson("/api/generators/{$generator->id}", $request);
$response->assertOk();
$this->assertDatabaseHas('generators', [
'id' => $generator->id,
'generator_set_id' => $generator->generatorSet->id,
// Testing for json requires arrows for accessing the data
// For Collection data, you should use numbers to access the indexes
// Note: Mysql dose not guarantee array order if i recall. Dont quote me on that but i'm pretty sure i read that somewhere. But for testing this works
'json_field_one->0' => 'array-data',
'json_field_one->1->more-data' => 'cool',
// to access properties just arrow over to the property name
'json_field_one->data' => 'some-data',
'json_field_one->collection->data' => 'some-more-data',
// Nested Collection
'json_field_one->collection->0->key' => 'value',
// Janky way to test for empty array
// Not really testing for empty
// only that the 0 index is not set
'json_field_two->0' => null,
]);
}
Note: The below solution is tested on Laravel Version: 9.x and Postgres version: 12.x
and the solution might not work on lower version of laravel
There would be two condition to assert json column into database.
1. Object
Consider Object is in json column in database as shown below:
"properties" => "{"attributes":{"id":1}}"
It can assert as
$this->assertDatabaseHas("table_name",[
"properties->attributes->id"=>1
]);
2. Array
Consider array is in json column as shown below:
"properties" => "[{"id":1},{"id":2}]"
It can assert as
$this->assertDatabaseHas("table_name",[
"properties->0->id"=>1,
"properties->1->id"=>2,
]);
Using json_encode on the value worked for me:
$this->assertDatabaseHas('users', [
'name' => 'Gaurav',
'attributes' => json_encode([
'gender' => 'Male',
'nationality' => 'Indian',
]),
]);

Resources