How to count the quantity of iten in every group on eloquent - php

I'm trying to group some records entries based on their statuses, however I just do not want the entries, but rather how many entries I have by status
This is my query :
CallItem::whereBetween('scheduled_date', [$startDate, $endDate])->get()->groupBy('status')->toArray()
That are the result:
array:4 [▼
"swapping" => array:4 [▼
0 => array:24 [▶]
1 => array:24 [▶]
2 => array:24 [▶]
3 => array:24 [▶]
]
"confirmed" => array:3 [▼
0 => array:24 [▶]
1 => array:24 [▶]
2 => array:24 [▶]
]
"canceled" => array:6 [▼
0 => array:24 [▶]
1 => array:24 [▶]
2 => array:24 [▶]
3 => array:24 [▶]
4 => array:24 [▶]
5 => array:24 [▶]
]
"scheduled" => array:5 [▼
0 => array:24 [▶]
1 => array:24 [▶]
2 => array:24 [▶]
3 => array:24 [▶]
4 => array:24 [▶]
]
]
But i want something like this:
array:4[▼
0 => 4,
1 => 3,
2 => 6,
3 => 5
]
only the size of the array in "swapping, confirmed, canceled, scheduled" and with no index.
How can i do this query ?

The map function would be a good choice. Don't call to toArray yet:
$totals = $result->map(function ($item) { return $item->count(); });
All together:
$totals = CallItem::whereBetween('scheduled_date', [$startDate, $endDate])
->get()
->groupBy('status')
->map(function ($group) { return $group->count(); });
Use array_flatten to then remove the indexes.

If you want to count using the database, you can use DB::raw.
$count = \DB::table('call_items')
->select(\DB::raw('count(status) as count'), 'status')
->groupBy('status')
->whereBetween('scheduled_date', [$startDate, $endDate])
->get();
This will return several objects with the status and a count per status.

Related

How do I add new item with key to collection in Laravel?

I have a Laravel collection $Data. When I code outputs
dd($Data); // it outputs the following
Illuminate\Support\Collection {#1344 ▼
#items: array:3 [▼
0 => {#1342 ▶}
1 => {#1334 ▶}
2 => {#1346 ▶}
]
}
$Data->push(['Total'=>600]);
dd($Data);
When I push a Total, it does inserts but output is not as expected.
Illuminate\Support\Collection {#1344 ▼
#items: array:4 [▼
0 => {#1342 ▶}
1 => {#1334 ▶}
2 => {#1346 ▶}
3 => array:1 [▼
"Total" => 600
]
]
}
How do I get 3 => {#1353▶) ?
You're pushing an Array to $Data, while the other items in that Collection are Objects (stdClass or similar). To make this consistent, use casting:
$Data->push((object)['Total' => 600]);
Now you should see 3 => {#...} instead of 3 => array:1.

PHP - adding to multi dimensional array adds new arrays to the first array element rather than the correct element

I have a 'parent' array that I'm reading and based on some values I read in a child array of that parent I create a new child array. i.e. I sum the number of 'products' in the child array to create a new child array.
The new child array is being created correctly BUT rather than create the new child array in the corresponding parent array element, my logic is placing all of the new child arrays in the first element of the parent. Please help.
foreach ($orders as $order) {
$orderResource = new OrderResource(Order::findOrFail($order['id']));
$ordersAll[] = $orderResource;
foreach (($orderResource['products']) as $product) {
if (array_key_exists($product['productType'],$product_array)) {
// array_push($product_array, $product['productType']);
$product_array[$product['productType']] += (int)$product['quantity'];
}
else $product_array[$product['productType']] = (int)$product['quantity'];
}
$ordersAll['product'][]= $product_array;
$product_array=[];
}
Result: rather than a new 'product' array being in each array element they're all in index 0.
array:22 [▼
0 => array:9 [▶]
"product" => array:21 [▶]
1 => array:9 [▶]
2 => array:9 [▶]
3 => array:9 [▶]
4 => array:9 [▶]
5 => array:9 [▶]
6 => array:9 [▶]
7 => array:9 [▶]
8 => array:9 [▶]
9 => array:9 [▶]
10 => array:9 [▶]
11 => array:9 [▶]
12 => array:9 [▶]
13 => array:9 [▶]
14 => array:9 [▶]
15 => array:9 [▶]
16 => array:9 [▶]
17 => array:9 [▶]
18 => array:9 [▶]
19 => array:9 [▶]
20 => array:9 [▶]
]
So, what I'd like is to have each array index to contain a new 'product_sum' array. This will contain key values for all the Product types found and a sum of the 'quantity'.
current:
0 => array:9 [▼
"refId" => "8e24cc331a73002b0c2da4bc7a62c647"
"Currency" => "USD"
"Symbol" => "$"
"Amount" => "315.50"
"created_at" => "2020-12-08T03:32:09.000000Z"
"updated_at" => "2020-12-08T03:32:09.000000Z"
"legs" => array:2 [▶]
"travellers" => array:3 [▶]
"products" => array:3 [▼
0 => array:13 [▶]
1 => array:13 [▶]
2 => array:13 [▶]
]
]
what I'm after is (in each parent array index):
0 => array:9 [▼
"refId" => "8e24cc331a73002b0c2da4bc7a62c647"
"Currency" => "USD"
"Symbol" => "$"
"Amount" => "315.50"
"created_at" => "2020-12-08T03:32:09.000000Z"
"updated_at" => "2020-12-08T03:32:09.000000Z"
"legs" => array:2 [▶]
"travellers" => array:3 [▶]
"products" => array:3 [▼
0 => array:13 [▶]
1 => array:13 [▶]
2 => array:13 [▶]
"product_sum" => array:1 [▼
0 => array:2 [▼
"ticket" => 5
"bag" => 1
This line is forcing all the product arrays into the element named product of $ordersAll:
$ordersAll['product'][]= $product_array;
Not sure why you are interacting with a Resource this way but you can just reorder this to remove the problem with knowing the current index for $ordersAll:
foreach ($orders as $order) {
$orderResource = new OrderResource(Order::findOrFail($order['id']));
$product_array = [];
foreach ($orderResource['products'] as $product) {
if (array_key_exists($product['productType'], $product_array)) {
$product_array[$product['productType']] += (int)$product['quantity'];
} else {
$product_array[$product['productType']] = (int)$product['quantity'];
}
}
// TODO:
// need the code to add $product_array to $orderResource
$ordersAll[] = $orderResource;
}
Though you should be able to build this list from a couple Collection methods and no need of looping anything yourself:
Order::findOrFail(...)->products->groupBy('productType')->map->sum('quantity');
I beleive this is the issue
$ordersAll[] = $orderResource;
...
$ordersAll['product'][]= $product_array;
You are adding the order to the ordersAll array, but then adding and overwriting the same product key each time.

PHP Get a specific property from an array of objects with different array count

I am in a confusing situation right now.
So, I have an array of objects
array:3 [▼
0 => array:5 [▶]
1 => array:2 [▶]
2 => array:10 [▶]
]
Each array items contains another array which will have objects
array:3 [▼
0 => array:5 [▼
0 => {#215 ▼
+"DefaultTimeLength": 40
+"ProgramID": 4
+"NumDeducted": 1
+"ID": 245
+"Name": "30-Swedish-Massage"
}
1 => {#216 ▼
+"DefaultTimeLength": 70
+"ProgramID": 4
+"NumDeducted": 1
+"ID": 246
+"Name": "60-Swedish-Massage"
}
2 => {#217 ▶}
3 => {#218 ▶}
4 => {#219 ▶}
]
1 => array:2 [▶]
2 => array:10 [▶]
]
What I want to achieve is, I want to get the 'ID' and 'Name' as an array for every array of objects from this array. Since, every array inside the main array have different counts, I cannot use a FOR loop, to get the required data.
Any ideas?
use nested foreach loop e.g:
foreach($main as $m){
foreach($m as $item){
echo $item->ID ." ".$item->Name;
}
}
use 2 foreach loop inside eachother
foreach ($array as $item) {
foreach ($item as $sub) {
echo $sub['ID'] . " " . $sub['Name'] . "<br>";
}
}
your full code will be something like this

Merge 2 arrays by their index in each row [duplicate]

This question already has answers here:
PHP's array_merge_recursive behaviour on integer keys
(5 answers)
Closed 5 months ago.
I have 2 arrays, each will always have the same number of rows and same number of values per row.
I need to merge the 2 arrays together, to combine the results on each row, but in a particular way (there will always be only 3 results per row on each array too):
For example, for each row, take the first result of each array, and put them next to each other, then the second result of each array, and put them next to each other, then finally the third.
So Array 1's value will always precede Array 2's value (example shown below):
Array 1:
array:7 [▼
24 => array:3 [▼
0 => 0
1 => 0.66666666666667
2 => 0.66666666666667
]
25 => array:3 [▶]
26 => array:3 [▶]
27 => array:3 [▶]
29 => array:3 [▶]
30 => array:3 [▶]
31 => array:3 [▶]
]
Array 2:
array:7 [▼
24 => array:3 [▼
0 => 0.375
1 => 0.42857142857143
2 => 0.55555555555556
]
25 => array:3 [▶]
26 => array:3 [▶]
27 => array:3 [▶]
29 => array:3 [▶]
30 => array:3 [▶]
31 => array:3 [▶]
]
Intended Combined Array Format:
array:7 [▼
24 => array:6 [▼
0 => 0
1 => 0.375
2 => 0.66666666666667
3 => 0.42857142857143
4 => 0.66666666666667
5 => 0.55555555555556
]
25 => array:6 [▶] ...
Current loop which returns the incorrect layout:
$results = array();
foreach ($questionDetails as $key => $question) {
for ($i = 0; $i < 3; $i++) {
$results[$key][] = $array1[$key] + $array2[$key];
}
}
Returns:
array:7 [▼
24 => array:3 [▼
0 => array:3 [▼
0 => 0
1 => 0.66666666666667
2 => 0.66666666666667
]
1 => array:3 [▼
0 => 0
1 => 0.66666666666667
2 => 0.66666666666667
]
2 => array:3 [▼
0 => 0
1 => 0.66666666666667
2 => 0.66666666666667
]
]
25 => array:3 [▶]
26 => array:3 [▶]
27 => array:3 [▶]
29 => array:3 [▶]
30 => array:3 [▶]
31 => array:3 [▶]
]
I'm unsure why my loop isn't just adding the three values from each row together - but then I think they still won't be in the right order, but I'm unsure of how to approach this.
Many thanks.
This is the "unfancy" (but save) solution if I understand your question correctly - all keys are preserved an set as desired:
$array1;
$array2;
$results = array();
foreach ($questionDetails as $key => $question1) {
$question2 = $array2[$key];
$tp = array();
$tp[0] = $question1[0];
$tp[1] = $question2[0];
$tp[2] = $question1[1];
$tp[3] = $question2[1];
$tp[4] = $question1[2];
$tp[5] = $question2[2];
$results[$key] = $tp;
}
EDIT: There is a way more flexible way to implement this where the number of arguments may vary (see PHP: array_merge() in alternate order (zip order)?).
$array1;
$array2;
function array_zip(...$arrays) {
return array_merge(...array_map(null, ...$arrays));
}
$results = array();
foreach ($questionDetails as $key => $question1) {
$results[$key] = array_zip($question1,$array2[$key]);
}
I would do this:
$combined = array();
foreach($array1 as $key => $value){
$combined[$key] = array();
foreach($value as $key2 => $value2){
$combined[$key][] = $value2;
$combined[$key][] = $array2[$key][$key2];
}
}
For a variable number of records.

Php sorting based on ID and ParentID

i have the following array structure:
| ID | CategoryName | ParentID
_________________________________
1 | Movies | -1
_________________________________
2 | Series | -1
_________________________________
3 | ActionMovies | 1
_________________________________
4 | HorrorMovies | 1
_________________________________
5 | ComedySeries | 2
_________________________________
6 | TVShows | -1
My goal is to reach the following structure
Goal:
| ID | CategoryName | ParentID
_________________________________
1 | Movies | -1
_________________________________
3 | ActionMovies | 1
_________________________________
4 | HorrorMovies | 1
_________________________________
2 | Series | -1
_________________________________
5 | ComedySeries | 2
_________________________________
6 | TVShows | -1
Or explained in word:
Parent-Categories have ParentID = -1 (Example Movies)
All categories keep their original ID-Number
Should come listed directly after their ParentCategory (Example ActionMovies)
RootCategories without Children, come listed at the end of array. (Example TVShows)
How can i achieve this best with PHP? I have no access to the original Mysql query, so that is not an option :)
i have started with this code, but i am not sure it is the right path, and with minimal efforts/readability
$tmpList = Categories_Models_Main::getAllCategories();
$categoryData = array();
foreach ($tmpList as $index => $categoryObject) {
$categoryData[] = array('id' => $categoryObject->id,
'CategoryName' => $categoryObject->parentId,
'name' => $categoryObject->name);
}
///let us assume $categoryData is original state.
///Beginning of manipulation and re-sorting of $tmpList
foreach ($categoryData as $key => $value) {
$mainId[$key] = $value['id'];
$parentId[$key] = $value['parentId'];
}
array_multisort($parentId, $mainId, $categoryData);
Split the main array into two, one with those nodes that doesn't have childs and other with rests of items.
Do the sorting into array of items with array_multisort function and do too a sorting into array of categories without childs using the criteria that you want. The final step will be push the array without childs to the other.
This form isn't the most efficient, but to have a first approach is valid, after this, you can dispense time optimizing the code.
$input = array(
array("foo", "bar", "5"),
array("barr", "baz", "9"),
array("nyan", "nyu", "2")
);
usort($input, function($a, $b) {
if($a[2] < $b[2]) {
return -1;
} else if($a[2] > $b[2]) {
return 1;
} else {
return 0;
}
});
var_dump($input);
Do you mean something like this? The idea is to manually compare the contents of the array using condition you know. Since the thing what is to be sorted is unique, the logic how to sort must be always implemented. With PHP, PHP’s sorting functions most of time does it correctly.
I am pretty sure that this does not answer your question, but might give you some ideas how to make your life easier. This is javascript approach of the problem, but this way you won't even have to think about sorting anything. You just provide parents and children and it is sorted for you and ready to use. A pretty nice way in my opinion. Yet it is probably irrelevant to what you are trying to do, but maybe for some other similar problem you would see this as a solution: https://developers.google.com/chart/interactive/docs/gallery/orgchart
The only way to solve this problem is by using a bottom up approach (i am referring to the pyramids).
Explanation
We need to start with rows (entries) within an array that do not have parents. In my case, it's any element that has "parent_id = 0". Once we have those, we need to build children elements for each parent element.
The latter part would be done recursively by calling sorting method until the element which we are processing has not children. The results from the sorting method are passed down to the previous array point until the array is complete.
Code
Class Categories {
private $cats;
public function getAllCategoriesSorted() {
/**
* $this->cats = [
* 'id' => x, 'parent_id' => x
* ];
*/
$this->cats = Category::get()->toArray();
# find categories with no parents
$keys = array_keys(array_column($this->cats, 'parent_id'), 0);
$return = [];
# loop through each and populate each one
foreach ($keys as $key) {
$return[$this->cats[$key]['id']] = $this->sortCategories($this->cats[$key]);
}
dd($return);
}
private function sortCategories($currentElement) {
# we need to check if current element has any children
$keys = array_keys(array_column($this->cats, 'parent_id'), $currentElement['id']);
if ($keys === false || empty($keys)) {
# we are dealing with childless element, we should return it as it is
return $currentElement;
}
# we are dealing with element that has children, we need to loop through each child
$currentElement['children'] = [];
foreach ($keys as $key) {
$currentElement['children'][$this->cats[$key]['id']] = $this->sortCategories($this->cats[$key]);
}
return $currentElement;
}
}
Example result
array:2 [▼
65 => array:4 [▼
"id" => 65
"name" => "Parent 1"
"parent_id" => 0
"children" => array:14 [▼
66 => array:4 [▼
"id" => 66
"name" => "Child 1"
"parent_id" => 65
"children" => array:22 [▶]
]
87 => array:4 [▼
"id" => 87
"name" => "Child 2"
"parent_id" => 65
"children" => array:31 [▶]
]
117 => array:4 [▶]
118 => array:4 [▶]
120 => array:4 [▶]
124 => array:4 [▶]
125 => array:4 [▶]
127 => array:4 [▶]
225 => array:4 [▶]
305 => array:4 [▶]
434 => array:4 [▶]
321 => array:4 [▶]
348 => array:4 [▶]
468 => array:4 [▶]
]
]
64 => array:4 [▼
"id" => 64
"name" => "Parent 2"
"parent_id" => 0
"children" => array:5 [▼
128 => array:4 [▶]
132 => array:4 [▼
"id" => 132
"name" => "Child 3"
"parent_id" => 64
"children" => array:22 [▼
202 => array:3 [▶]
203 => array:3 [▼
"id" => 203
"name" => "Child 4"
"parent_id" => 132
]
204 => array:3 [▶]
205 => array:3 [▶]
206 => array:3 [▶]
207 => array:3 [▶]
208 => array:3 [▶]
209 => array:3 [▶]
210 => array:3 [▶]
211 => array:3 [▶]
212 => array:3 [▶]
213 => array:3 [▶]
214 => array:3 [▶]
215 => array:3 [▶]
216 => array:3 [▶]
217 => array:3 [▶]
218 => array:3 [▶]
220 => array:3 [▶]
221 => array:3 [▶]
222 => array:3 [▶]
223 => array:3 [▶]
224 => array:3 [▶]
]
]
134 => array:4 [▶]
394 => array:4 [▶]
454 => array:4 [▶]
]
]
]

Categories