Merge a Laravel array of Collections, and add new properties/attributes [closed] - php

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a collection array of 'Products', as seen from the dump below.
Illuminate\Support\Collection {#918 ▼
#items: array:12 [▼
0 => App\Product {#934 ▶}
1 => App\Product {#943 ▶}
2 => App\Product {#959 ▶}
3 => App\Product {#968 ▶}
4 => App\Product {#984 ▶}
5 => App\Product {#993 ▶}
6 => App\Product {#1009 ▶}
7 => App\Product {#1018 ▶}
8 => App\Product {#1034 ▶}
9 => App\Product {#1043 ▶}
10 => App\Product {#1059 ▶}
11 => App\Product {#1068 ▶}
]
}
This array has ONLY two unique products;
App\Product {#934 ▼
...
+wasRecentlyCreated: false
#attributes: array:10 [▼
"id" => 1
"slug" => "26027686555545"
"details" => App\DispatchStock {#900 ▼
...
#attributes: array:9 [▼
...
"quantity" => 3
"created_at" => "2020-05-04 15:56:07"
]
...
}
]
...
}
and
App\Product {#943 ▼
...
+wasRecentlyCreated: false
#attributes: array:10 [▼
"id" => 2
"slug" => "26027687444410"
"details" => App\DispatchStock {#899 ▼
...
#attributes: array:9 [▼
...
"quantity" => 5
"created_at" => "2020-05-04 15:56:07"
]
...
}
]
...
}
duplicated 6 times each (with varying 'quantity's).
I want to loop through the collection array of 'Products', merge all the duplicates, and return an array of just the unique products.And have something like:
Illuminate\Support\Collection {#918 ▼
#items: array:2 [▼
0 => App\Product {#934 ▶}
1 => App\Product {#943 ▶}
]
}
While appending a new attribute 'combined_available_quantity' (the sum of all the 'quantity's of the Products) to the 'details' property of each of the unique Products.
For example, I want one of the final 'Product's to look like:
App\Product {#943 ▼
...
+wasRecentlyCreated: false
#attributes: array:10 [▼
"id" => 2
"slug" => "26027687444410"
"details" => App\DispatchStock {#899 ▼
...
#attributes: array:9 [▼
...
"quantity" => 5
"created_at" => "2020-05-04 15:56:07"
"combined_available_quantity" => 27
]
...
}
]
...
}
I already started with the code below.
...
$combinedProducts = collect();
foreach ($products as $product) {
$combinedProducts = $combinedProducts->each(function($combinedProduct) use ($combinedProducts, $product) {
if ($combinedProduct->slug == $product->slug) {
$qty = $product->details->quantity + $combinedProduct->details->quantity;
$combinedProduct->details->setAttribute('combined_available_quantity', $qty);
} else {
$product->details->setAttribute('combined_available_quantity', $product->details->quantity);
$combinedProducts->push($product);
}
});
$combinedProducts = $combinedProducts->values();
}
But it's buggy, and doesn't give me required results.
I need a better approach. Thanks.

$collect->groupBy('slug')->map(function($item){
return $item->sum('quantity');
})

Related

Laravel Object of class stdClass could not be converted to string. Still object when using toArray();

I have a table that I want to export via excel. I use the method toArray(); and still I get the result as object. Here is my sample code
$items = \DB::table('users')
->join('finances', 'users.id','=','finances.user_id')
->join('schoolyears', 'users.school_id','=','schoolyears.school_id')
->select('users.name','users.phone','users.section_id', 'users.student_school_id','finances.amount','finances.description','schoolyears.name as syear','finances.date')
->where('finances.date', '=' ,(\DB::raw("(select max(`date`) from finances f where finances.user_id=f.user_id)")))
->where('users.role','=','4' )
->where('users.school_id','=', $sid)
->get()->toArray();
// dd($items);
} else {
return redirect('home')->with('error', 'Invalid access');
}
\Excel::create($this->page_title . 's', function ($excel) use ($items) {
$excel->sheet($this->page_title . 's', function ($sheet) use ($items) {
$sheet->fromArray($items);
});
The result I get when i dd($items)
array:2 [▼
0 => {#558 ▼
+"name": "Annamarie Morar"
+"phone": "(0997) 212-7919"
+"section_id": null
+"student_school_id": "50"
+"amount": "500"
+"description": "New Pays"
+"syear": "SY-2019-2020"
+"date": "2019-11-14"
}
1 => {#561 ▶}
]
What i want is like this so that i can export it as an excel file
array:9 [▼
0 => array:10 [▼
"FirstName" => "Madelynn"
"LastName" => "Stokes"
"Gender" => "female"
"Birthday" => "2013-10-09"
"Address" => "78A/40 Goodwin Meadow, Poblacion, Iloilo City 1333 Nueva Ecija"
"PhoneNo" => "+63 (971) 659-8143"
"Parent" => "Deondre Stokes"
"SchoolID" => "521"
"RFID" => "173"
"Section" => null
]
1 => array:10 [▶]
2 => array:10 [▶]
3 => array:10 [▶]
4 => array:10 [▶]
5 => array:10 [▶]
6 => array:10 [▶]
7 => array:10 [▶]
8 => array:10 [▶]
]
You could convert each object to an array by transforming the Collection then turning the Collection into an array if you had to:
$items = DB::table(...)->.....->get()->transform(function ($item) {
return (array) $item;
})->toArray();
Laravel 6.x Docs - Collections - Methods - transform

Podio fields property is empty in Item object

This has just started happening with no changes to our implementation.
When I query (it seems any item) the API is no longer returning data in the fields property.
PodioItem {#354 ▼
-__attributes: array:32 [▼
"item_id" => 1234567890
"external_id" => null
"title" => "INV-1234567890-Deposit"
"link" => "[redacted]"
"rights" => array:8 [▶]
"created_on" => "2019-09-10 22:28:37"
"app_item_id_formatted" => "1310"
"app_item_id" => 1310
"created_by" => PodioByLine {#362 ▶}
"created_via" => PodioVia {#363 ▶}
"initial_revision" => PodioItemRevision {#364 ▶}
"current_revision" => PodioItemRevision {#367 ▶}
"fields" => PodioVia {#370 ▼
-__attributes: []
-__belongs_to: array:2 [▶]
-__properties: array:5 [▶]
-__relationships: []
#__id_column: null
}
"like_count" => null
"is_liked" => false
"ratings" => array:1 [▶]
"user_ratings" => array:1 [▶]
"last_event_on" => "2019-09-10 23:17:06"
"participants" => []
"tags" => []
"refs" => []
"linked_account_id" => null
"subscribed" => false
"invite" => []
"app" => PodioApp {#371 ▶}
"ref" => PodioReference {#372 ▶}
"reminder" => PodioReminder {#373 ▶}
"recurrence" => PodioRecurrence {#374 ▶}
"linked_account_data" => PodioLinkedAccountData {#375 ▶}
"comments" => PodioLinkedAccountData {#376 ▶}
"revisions" => PodioVia {#392 ▶}
"files" => PodioVia {#401 ▶}
]
-__belongs_to: null
-__properties: array:38 [▶]
-__relationships: array:15 [▶]
#__id_column: "item_id"
}
You can see __attributes are empty for fields. Again, for every item I have tested and for several apps, it is the same.
As I said nothing has changed in our implementation - last week it was working fine.
Any ideas?

Laravel 5.6 Many to Many relationship throwing errors during display

**** UPDATE *******************************************************
I'm not sure why, but moving everything into the controllers index() method rather than having it in the show() method solved the problem. Don't know why it works, but it does.
Original Question:
Cant figure out what is wrong here, i have followed the docs, tried variations, etc... still no luck making this work correctly.
Model A: (Slide)
public function carousels() {
return $this->belongsToMany(Carousel::class)->withTimestamp()
}
Model B: (Carousel)
public function slides() {
return $this->belongsToMany(Slide::class)->withTimestamp()
}
Pivot Table
--------------------------------------------------
|carousel_id | slide_id | created_at | updated_at|
--------------------------------------------------
From Controller:
public function show(Carosuel $carousels) {
$carousels = $carousel->with('slides)->get();
return view('myView', compact(['carousels']));
}
In the following dump, the "slides" are not in the attributes object of the collection; however, they are in the relations object. Im not sure if this is normal behavior or if the slides array should be in the attributes object. If the latter is the case, then how does one go about making that happen?
$caousels dump:
Collection {#1320 ▼
#items: array:20 [▼
0 => Carousel {#798 ▼
#fillable: array:4 [▶]
#connection: "mysql"
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:7 [▼
"id" => 1
"name" => "Prof. Andre Gerlach"
"category" => "Dr."
"active" => 0
"deleted_at" => null
"created_at" => "2018-04-07 21:10:52"
"updated_at" => "2018-04-07 21:10:52"
]
#original: array:7 [▶]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: array:1 [▼
"slides" => Collection {#1300 ▼
#items: array:5 [▼
0 => Slide {#1023 ▶}
1 => Slide {#1024 ▶}
2 => Slide {#1025 ▶}
3 => Slide {#1026 ▶}
4 => Slide {#1027 ▶}
]
}
]
#touches: []
+timestamps: true
#hidden: []
#visible: []
#guarded: array:1 [▶]
}
1 => Carousel {#799 ▶}
2 => Carousel {#800 ▶}
In the View:
foreach($carousels as $carousel){
echo $carousel->name;
foreach($carousel->slides as $slide){
echo $slide->tag;
}
}
This throws the E_ERROR Invalid argument supplied for foreach() in view
If, however, I cast this to an array, it works. Problem is that i also need to paginate the results. Once i do, the slides array is again inaccessible.
public function show(Carosuel $carousels) {
// This works - slides are available to me in the view
$carousels = $carousel->with('slides)->get()->toarray();
// This DOESN'T work - slides are not available to me in the view
$carousels = $carousel->with('slides)->paginate(6)->toarray();
return view('myView', compact(['carousels']));
}
dump as array:
array:12 [▼
"current_page" => 1
"data" => array:6 [▼
0 => array:8 [▼
"id" => 1
"name" => "Prof. Andre Gerlach"
"category" => "Dr."
"active" => 0
"deleted_at" => null
"created_at" => "Apr 07 2018"
"updated_at" => "2018-04-07 21:10:52"
"slides" => array:5 [▼
0 => array:11 [▶]
1 => array:11 [▶]
2 => array:11 [▶]
3 => array:11 [▶]
4 => array:11 [▶]
]
]
1 => array:8 [▶]
2 => array:8 [▶]
3 => array:8 [▶]
4 => array:8 [▶]
5 => array:8 [▶]
]
"first_page_url" => "//localhost:3000/admin/carousel/show?page=1"
"from" => 1
"last_page" => 4
"last_page_url" => "//localhost:3000/admin/carousel/show?page=4"
"next_page_url" => "//localhost:3000/admin/carousel/show?page=2"
"path" => "//localhost:3000/admin/carousel/show"
"per_page" => 6
"prev_page_url" => null
"to" => 6
"total" => 20
The problem here is that, in the view, the slides key is no longer accessible. Throws following error (only if I use ->paginate()).
E_ERROR Trying to get property 'slides' of non-object
Everything I have read in the docs and from other sources show this to be a pretty basic operation. For the live of me, i cant figure out why its causing such an issue. I should be able to access this in the view by simply nesting a foreach.
Any help with this would be greatly appreciated.
In the following dump, the "slides" are not in the attributes object of the collection; however, they are in the relations object.
Yes this is normal.
This is where you have a problem:
public function show(Carosuel $carousels) {
// ...
return view('myView', compact(['carousels']));
}
Typehinting a model in a function is reserved for model binding. Which is not what you're doing here since you don't have an {id} or some other parameter in your route.
Remove the typehinting and call the model instead:
public function show() {
$carousels = Carousel::with('slides')->get();
return view('myView', compact(['carousels']));
}
If you'd like to remove the dependency from the method, you should do it in the constructor instead.
Edit:
While I don't see any other problem and the above solution should work, if it's true that ->toArray() works for you (but you still need pagination), you could just convert the underlying collection:
public function show() {
$carousels = Carousel::with('slides')->paginate();
$carousels->setCollection(collect($carousels->getCollection()->toArray()));
return view('myView', compact(['carousels']));
}
Can you try this?
Model B: (Carousel)
public function slides() {
return $this->hasMany(Slide::class)->withTimestamp();
}

Laravel - How to collect multiple array to single one

I've created a collection like this :
Collection {#651 ▼
#items: array:3 [▼
0 => array:3 [▼
"orderId" => "402457"
"orderCreated" => DateTime {#656 ▶}
"foods" => array:2 [▶]
]
1 => array:3 [▼
"orderId" => "402457"
"orderCreated" => DateTime {#661 ▶}
"foods" => array:2 [▶]
]
2 => array:3 [▼
"orderId" => "402457"
"orderCreated" => DateTime {#665 ▶}
"foods" => array:2 [▶]
]
]
}
I demand to achieve collection like this (with Laravel collection):
Collection {#651 ▼
#items: array:3 [▼
0 => array:3 [▼
"orderId" => "402457"
"orderCreated" => DateTime {#656 ▶}
"foods" => array:6 [▶]
]
]
}
Because orderId and orderCreated are all the same in arrays. I need to make single array that collect orderId and orderCreated with all foods.
Any suggestion?
You can take the data from the first one and just combine all of the food items. For instance like this:
$new = collect([
'orderId' => $old->first()->orderId,
'orderCreated' => $old->first()->orderCreated,
'foods' => $old->pluck('foods')->flatten(1),
]);
The exact implementation will depend on how you built your initial collection.

to to get data from specific index in multidimensional array to avoid use of many foreach loops

I am trying to get data in from multidimensional array without using foreach
i tried using in_array() function but not worked
$abc = array()
in_array($abc , $private_job->cities)
in_array() expects parameter 2 to be array, string given
on using $private_job->cities got the following result
Collection {#408 ▼
#items: array:2 [▼
0 => city {#416 ▼
+wasRecentlyCreated: false
#attributes: array:2 [▼
"id" => 7
"city_name" => "Gujranwala"
]
}
1 => city {#417 ▼
+wasRecentlyCreated: false
#attributes: array:2 [▶]
#original: array:4 [▼
"id" => 4
"city_name" => "Islamabad"
"pivot_private_jobabd_id" => 53
"pivot_city_id" => 4
]
}
]
}
whereas i am interested in getting
"id" => 7
"id" => 4
in an an array
$result = $private_job->cities->map(function($data){
return $data['id'];
})->all();

Categories