Laravel Collection: How to access object of object? - laravel

This is my query:
$productItems = ProductItemResource::collection(ProductItem::where('pd_id', $id)->get());
The output of query is this:
$output = [[
'id' => 1,
'serial' => "XXXXXXAA1",
'pd_item_info' =>[
'id' => 1,
'quantity' => 5,
'product_info' => [
'id' => 1,
'product_name' => 'Keyboard'
],
]
],[
'id' => 2,
'serial' => "XXXXXXAA2",
'pd_item_info' =>[
'id' => 2,
'quantity' => 10,
'product_info' => [
'id' => 2,
'product_name' => 'Monitor'
],
]
]];
This is my condition:
foreach ($output as $productItem) {
return $productItem->pd_item_info->product_info['product_name'];
// IT HAS AN ERROR WHERE I CAN'T ACCESS THE OBJECT OF OBJECT
}
Why I'm getting error accessing object of object when I use resource?

that the result is an array is not an object.
foreach($output as productItem) {
return $productItem['pd_item_info']['product_info']['product_name'];
}

Why you create a new collection?
$productItems = ProductItemResource::collection(ProductItem::where('pd_id', $id)->get());
Result of query already is collection
ProductItem::where('pd_id', $id)->get()

Related

How to access nested item in Rule::requiredIf() validation

I'm trying to validate an array inside a custom Request. The rule evaluates to required if two conditions are met:
attribute3 is true
another column from the same array is true
Here's what I'm doing:
public function rules()
{
return [
'attribute1' => 'required',
'attribute2' => 'required',
'attribute3' => 'required',
...
'attribute10.*.column3' => Rule::requiredIf(fn() => $this->attribute3), // <- array
'attribute10.*.column4' => Rule::requiredIf(fn() => $this->attribute3), // <- array
'attribute10.*.column5' => Rule::requiredIf(fn() => $this->attribute3), // <- array
];
}
What I really need is this:
'attribute10.*.column4' => Rule::requiredIf(fn($item <- magically hint this currently looped item) => $this->attribute3 && $item->column2 <- so I can use it like this), // <- array
Assuming the incoming request has a structure like the following:
[
'attribute1' => 1,
'attribute2' => 0,
'attribute3' => 1,
'attribute10' => [
[
'column1' => 1,
'column2' => 1,
'column3' => 0,
],
[
'column1' => 0,
'column2' => 1,
'column3' => 0,
],
],
]
You can set the rules array to a variable, and then loop over the attribute10 field array elements and merge each rule on the rules variable. Then you'll have access to the other elements on the nested array.
Ie:
public function rules()
{
$rules = [
'attribute1' => 'required',
'attribute2' => 'required',
'attribute3' => 'required',
];
foreach($this->attribute10 as $key => $item) {
array_merge($rules, [
'attribute10.'.$key.'.column2' => Rule::requiredIf($this->attribute3 && $item['column1']),
'attribute10.'.$key.'.column3' => Rule::requiredIf($this->attribute3 && $item['column2']),
//...
]);
}
return $rules;
}

How can I do store multidimensional array base on name in Laravel collection?

In image you can see name and I want to store on base of name
Array index 0 & 2 have the same name. And I want to store same name in one array
Like This:
Josue Koepp DDS => {
id=>2,
item_name=>"Domenic Labadie"
},
{
id=>0,
item_name=>"Prof. Jakayla Willms"
}
}
You can use groupBy()
$collection = collect([
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
['account_id' => 'account-x11', 'product' => 'Desk'],
]);
$grouped = $collection->groupBy('account_id');
$grouped->toArray();
/*
[
'account-x10' => [
['account_id' => 'account-x10', 'product' => 'Chair'],
['account_id' => 'account-x10', 'product' => 'Bookcase'],
],
'account-x11' => [
['account_id' => 'account-x11', 'product' => 'Desk'],
],
]
*/
In your case:
$lists = $lists->groupBy('name')->toArray();

How to insert all json file data in database?

I have JSON file and have data in it. I want to import all data in the database through DB seeders. I am getting an error Trying to get property name of non-object. I have multiple data how I can insert in the database?
public function run()
{
$json = File::get("public/kmz/WASASubdivisions.geojson");
$data = json_decode($json);
// dd($data);
foreach ($data as $obj){
Regions::create(array(
'name' => $obj[0]->Name,
'description' => $obj[0]->description,
'altitudeMode' => $obj[0]->altitudeMode,
'Town' => $obj[0]->Town,
'AC' => $obj[0]->AC,
'No_of_TW' => $obj[0]->No_of_TW,
'No' => $obj[0]->No,
'DC'=> $obj[0]->DC,
'HH_2017' => $obj[0]->HH_2017,
'FID' => $obj[0]->FID,
'Area_ha' => $obj[0]->Area_ha,
'Field_1' => $obj[0]->Field_1,
'Pop_Dens' => $obj[0]->Pop_Dens,
'Id' => $obj[0]->Id,
'Pop_2017' => $obj[0]->Pop_2017,
'Area_Sq'=> $obj[0]->Area_Sq,
));
}
}
Sample Json Format
31 => {#837
+"type": "Feature"
+"properties": {#838
+"Name": "Gujjar Pura"
+"description": null
+"altitudeMode": "clampToGround"
+"Town": "Shalimar Town"
+"AC": "31"
+"No_of_TW": "11"
+"No": "13"
+"DC": "38"
+"HH_2017": "30478"
+"FID": "31"
+"Area_ha": "648.327"
+"Field_1": "Gujjar Pura"
+"Pop_Dens": "54063.141167"
+"Id": "0"
+"Pop_2017": "196619"
+"Area_Sq": "3.63684"
}
+"geometry": {#839
+"type": "MultiPolygon"
+"coordinates": array:1 [
0 => array:1 [
0 => array:169 [ …169]
]
]
}
}
Let's support I have a model Post and I want to save additional data in JSON format in the posts table. In that case, we can use property $casts in Laravel. Which will cast our field value to whatever we gave.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table='posts';
protected $fillable = ['user_id', 'title', 'short_description', 'description', 'status', 'json_data'];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'json_data' => 'array',
];
}
Now we want to save data something like this
$data = [
'user_id' => 1,
'title' => 'abc',
'short_description' => 'test',
'description' => 'test',
'status' => true,
'json_data' => [
'additional_info' => '',
'post_image' => '',
...
],
];
$item = new Post;
$item->fill($data)->save();
This will save your json_data array values to JSON in the database. But when you will get data from the database it will convert that to array automatically.
For reference read this
since i am not a big fan of processing the json as a object
So the json_decode will accept the second arg so
$json = File::get("public/kmz/WASASubdivisions.geojson");
$data = json_decode($json,true);
dd($data);
foreach ($data as $obj)
{
Regions::create(array(
'name' => $obj['Name'],
'description' => $obj['description'],
'altitudeMode' => $obj['altitudeMode'],
'Town' => $obj['Town'],
'AC' => $obj['AC'],
'No_of_TW' => $obj['No_of_TW'],
'No' => $obj['No'],
'DC'=> $obj['DC'],
'HH_2017' => $obj['HH_2017'],
'FID' => $obj['FID'],
'Area_ha' => $obj['Area_ha'],
'Field_1' => $obj['Field_1'],
'Pop_Dens' => $obj['Pop_Dens'],
'Id' => $obj['Id'],
'Pop_2017' => $obj['Pop_2017'],
'Area_Sq'=> $obj['Area_Sq'],
));
}
Can You Post the dd() result and fileds sets of the table
public function run()
{
$json = File::get("public/kmz/WASASubdivisions.geojson");
$data = json_decode($json);
dd($data);
foreach ($data as $obj){
Regions::create(array(
'name' => $obj->Name,
'description' => $obj->description,
'altitudeMode' => $obj->altitudeMode,
'Town' => $obj->Town,
'AC' => $obj->AC,
'No_of_TW' => $obj->No_of_TW,
'No' => $obj->No,
'DC'=> $obj->DC,
'HH_2017' => $obj->HH_2017,
'FID' => $obj->FID,
'Area_ha' => $obj->Area_ha,
'Field_1' => $obj->Field_1,
'Pop_Dens' => $obj->Pop_Dens,
'Id' => $obj->Id,
'Pop_2017' => $obj->Pop_2017,
'Area_Sq'=> $obj->Area_Sq,
));
}
}
The attributes are under the properties key, but you're referencing them from the root of the object. e.g. $obj[0]->Name should be $obj[0]->properties->Name, etc.

Creating a collection from a multidimensional array?

I'm trying to make a collection from some arrays of data:
$myCollection = collect(
['product_id' => 1, 'price' => 200, 'discount' => '50'],
['product_id' => 2, 'price' => 400, 'discount' => '50']
);
When I loop out I would like to do:
foreach ($myCollection as $product) {
echo $product->price;
echo $product->discount;
}
But the underlying elements appear to still be in an arrays format, how can I achieve the above output?
If you want the inner arrays to be a collection, then you can do so as follows:
$myCollection = collect([
['product_id' => 1, 'price' => 200, 'discount' => '50'],
['product_id' => 2, 'price' => 400, 'discount' => '50']
])->map(function($row) {
return collect($row);
});
If you want the inner arrays to be objects, then you can do as follows:
$myCollection = collect([
['product_id' => 1, 'price' => 200, 'discount' => '50'],
['product_id' => 2, 'price' => 400, 'discount' => '50']
])->map(function($row) {
return (object) $row;
});
You can also iterate over each of the results...
$myCollection = collect([
['product_id' => 1, 'price' => 200, 'discount' => '50'],
['product_id' => 2, 'price' => 400, 'discount' => '50']
])->map(function($row) {
return (object) $row;
})->each(function($row) {
echo sprintf('ProductId: %d, Price: %d, Discount: %s'.PHP_EOL, $row->product_id, $row->price, $row->discount);
});
Output:
ProductId: 1, Price: 200, Discount: 50
ProductId: 2, Price: 400, Discount: 50
Simple as you are getting a collection of an associative arrays because you are collecting arrays elements, so the collection helper doesn't want to modify it in case you need it as array.
Knowing this, if you want to collect objects you should pass an element of object type.
You can cast object data type into the array, like this:
$myCollection = collect( (object) array(
(object) ['product_id' => 1, 'price' => 200, 'discount' => '50'],
(object) ['product_id' => 2, 'price' => 400, 'discount' => '50'])
);
Then you have a collection of objects !
Function collect() takes array of elements. You can fix your code also by enclosing all the elements into [] and then converting Collection elements to objects instead of leaving them to be arrays
$myCollection = collect([
(object)(['product_id' => 1, 'price' => 200, 'discount' => '50']),
(object)(['product_id' => 2, 'price' => 400, 'discount' => '50'])
]
);
foreach ($myCollection as $product) {
echo $product->price;
echo $product->discount;
}
There's a syntax error in your collection definition:
$myCollection = collect([
['product_id' => 1, 'price' => 200, 'discount' => '50'],
['product_id' => 2, 'price' => 400, 'discount' => '50']
]);
Also, since you're using a Collection, you no longer need to use a foreach loop:
$myCollection->each(function ($item) {
echo $item['price'];
})

Result by model

I have this query:
$data = TableRegistry::get('Dogs');
$data = $data->find('all')
->contain(['Foods'])
->select(['name','breed','sex','Foods.name','Foods.quality'])
->last()
->toArray();
It returns this result:
[
'name' => 'Dug',
'breed' => 'Golden Retriever',
'sex' => 'Male',
'food' => [
'name' => 'Best Food',
'quality' => 'A+'
]
]
I want to know if there is any way to make CakePHP return the result as:
[
'dog' => [
'name' => 'Dug',
'breed' => 'Golden Retriever',
'sex' => 'Male'
],
'food' => [
'name' => 'Best Food',
'quality' => 'A+'
]
]
How would I do this? I am pretty sure it's very simple, but I can't figure it out.
Maybe like this:
$data => [
'dog' => [
'name' => $dog->name,
'breed' => $dog->breed,
'sex' => $dog->sex
],
'food' => $dog->foods
];
$this->set('data', $data);
So following Salines' post, I decided to just build something quick and easy to work with since the content is a bit more dynamic than the example I posted.
$data = TableRegistry::get($this->table);
$data = $data->find()
->contain($associated)
->select($this->data_fields)
->last()
->toArray();
$main = strtolower(Inflector::singularize($this->table));
$data[$main] = [];
foreach ($data as $key => $value) {
if(!is_array($value)) {
$data[$main][$key] = $value;
unset($data[$key]);
}
}

Resources