Convert data rows to 1 object - laravel

Reading Laravel 6 rows like
{"filter_options":[
{"id":5,"key":"category_id","value":"2","created_at":"2020-02-10 18:23:48"},
{"id":4,"key":"only_with_images","value":"1","created_at":"2020-02-10 18:23:48"}
]
}
I need to convert data in 1 object, like
{
category_id : 2,
only_with_images :"1"
}
I know how that could be implemented with a common circle, but are there some collection mapping methods for this?
Thanks!

I am not sure if your data is a collection or not, but let's assume this is the data
$array = ['filter_options' => [
['id' => 5, 'key' => 'category_id', 'value' => 2, 'created_at' => '2020-02-10 18:23:48'],
['id' => 4, 'key' => 'only_with_images', 'value' => 1, 'created_at' => '2020-02-10 18:23:48'],
]];
you only need to do this
//after php 7.4
return collect($array['filter_options'])->flatMap(fn ($item) => [$item['key'] => $item['value']]);
//before php 7.4
return collect($array['filter_options'])->flatMap(function ($item) {
return [$item['key'] => $item['value']];
});
Note: obviously this is array syntax to access the properties($item['key']), if your data soruce is from laravel eloquent, you may not need collect() helper method and you need to use the object way to access the properties like $item->key.

Related

Laravel update specific data from model where it doesn't have array of ids

I want to update all model data except some from an array of ids, how is this kind of thing possible with eloquent?
What i'm doing:
Creating or updating events and setting availability to 0 also gatherings the ids in a foreach loop for each event
$rv = CalendarSchedule::updateOrCreate([
'date_start' => $import['start']->format('Y-m-d H:i:s'),
'date_end' => $import['end']->format('Y-m-d H:i:s'),
'operator_id' => $operator->id
],[
'location_id' => $operator->place_id,
'available' => 0,
'block' => 1
]);
array_push($ids, $rv->id);
Now when the foreach loop ends i want to update all the CalendarSchedule data except those in the ids array and set available => 1
Using made it work.
DB::table('calendar_schedules')->whereNotIn('id', $ids)->update([
'available' => 1
]);

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

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',
]),
]);

Using returned data from controller in Laravel blade

With Laravel, I'm returning data from controller to blade. How to access to datesValid value in blade directly? I want to print the value in that case true.
Controller code:
if (empty($source)) {
return ["recordsTotal" => 0, "recordsFiltered" => 0, 'data' => [], 'datesValid' => $datesValid];
} else {
return ["recordsTotal" => $source['count'][0]['count'], "recordsFiltered" => $source['count'][0]['count'], 'data' => $source['result'], 'datesValid' => $datesValid ];
}
please take a look on this: laravel blade
if from controller you are sending it like this:
return view('x', ['result' => $result]);
and result is an object containing these data.
So you can do:
{{$result->datesValid}}
if it is an array so you can do:
{{$result['datesValid']}}

Will Model::updateOrCreate() update a soft-deleted model if the criteria matches?

Let's say I have a model that was soft-deleted and have the following scenario:
// EXISTING soft-deleted Model's properties
$model = [
'id' => 50,
'app_id' => 132435,
'name' => 'Joe Original',
'deleted_at' => '2015-01-01 00:00:00'
];
// Some new properties
$properties = [
'app_id' => 132435,
'name' => 'Joe Updated',
];
Model::updateOrCreate(
['app_id' => $properties['app_id']],
$properties
);
Is Joe Original now Joe Updated?
OR is there a deleted record and a new Joe Updated record?
$variable = YourModel::withTrashed()->updateOrCreate(
['whereAttributes' => $attributes1, 'anotherWhereAttributes' => $attributes2],
[
'createAttributes' => $attributes1,
'createAttributes' => $attributes2,
'createAttributes' => $attributes3,
'deleted_at' => null,
]
);
create a new OR update an exsiting that was soft deleted AND reset the softDelete to NULL
updateOrCreate will look for model with deleted_at equal to NULL so it won't find a soft-deleted model. However, because it won't find it will try to create a new one resulting in duplicates, which is probably not what you need.
BTW, you have an error in your code. Model::updateOrCreate takes array as first argument.
RoleUser::onlyTrashed()->updateOrCreate(
[
'role_id' => $roleId,
'user_id' => $user->id
],
[
'deleted_at' => NULL,
'updated_at' => new \DateTime()
])->restore();
Like this you create a new OR update an exsiting that was soft deleted AND reset the softDelete to NULL
Model::withTrashed()->updateOrCreate([
'foo' => $foo,
'bar' => $bar
], [
'baz' => $baz,
'deleted_at' => NULL
]);
Works as expected (Laravel 5.7) - updates an existing record and "undeletes" it.
I tested the solution by #mathieu-dierckxwith Laravel 5.3 and MySql
If the model to update has no changes (i.e. you are trying to update with the same old values) the updateOrCreate method returns null and the restore() gives a Illegal offset type in isset or empty
I got it working by adding withTrashed so that it will include soft-deleted items when it tries to update or create. Make sure deleted_at is in the fillable array of your model.
$model = UserRole::withTrashed()->updateOrCreate([
'creator_id' => $creator->id,
'user_id' => $user->id,
'role_id' => $role->id,
],[
'deleted_at' => NULL
])->fresh();
try this logic..
foreach ($harga as $key => $value) {
$flight = salesprice::updateOrCreate(
['customerID' => $value['customerID'],'productID' => $value['productID'], 'productCode' => $value['productCode']],
['price' => $value['price']]
);
}
it work for me

Resources