I'm trying to print out shopping cart orders, however, instead of displaying all products from that order I want to group the orders by the order ID so that I can display the sum of the order and link to a detail page.
---------------------------------------
date order number total
---------------------------------------
today 1234WEDK 600
---------------------------------------
today 1234WEDK 500
---------------------------------------
---------------------------------------
date order number total
---------------------------------------
today 1234WEDK 1100
---------------------------------------
Here's a sample array
array:2 [▼
0 => array:9 [▼
"id" => 57
"order_id" => 51
"order_hash" => "1234WEDK"
"price" => 600
]
1 => array:9 [▼
"id" => 58
"order_id" => 51
"order_hash" => "1234WEDK"
"price" => 500
]
]
Assuming you are getting your data from a database, you should make it to do all the calculations for you
SELECT order_hash, date, sum(price) as total FROM cart GROUP BY order_hash
$data = [
[
"id" => 57,
"order_id" => 51,
"order_hash" => "1234WEDK",
"price" => 600
],
[
"id" => 58,
"order_id" => 51,
"order_hash" => "1234WEDK",
"price" => 500
],
[
"id" => 59,
"order_id" => 1111,
"order_hash" => "1234ABCD",
"price" => 200
]
];
$result = array_reduce($data, function($acc, $x) {
if (!array_key_exists($x['order_hash'], $acc)) {
$acc[$x['order_hash']] = 0;
}
$acc[$x['order_hash']] += $x['price'];
return $acc;
}, []);
echo json_encode($result, JSON_PRETTY_PRINT), PHP_EOL;
Output
{
"1234WEDK": 1100,
"1234ABCD": 200
}
That solution is mostly crap tho because the function is totally tangled up with multiple intentions and responsibilities. It's looking up object properties, grouping, and summing values all in one. Blech.
Functional Programming in PHP can be pretty verbose, but that doesn't mean it should be entirely dismissed.
What if I told you … the entire solution could be reduced to this ?
// your reusable computation
$sumOrdersByHash = comp (map (function($xs) {
return [
'hash' => prop ('order_hash') (head ($xs)),
'sum' => sum (map (prop('price')) ($xs))
];
})) (group_by (prop ('order_hash')));
// run computation
$result = $sumOrdersByHash($data);
All you need are these reusable prerequisites. Bwahahahaha …
function id ($x) { return $x; }
function head ($xs) { return $xs[0]; }
function tail ($xs) { return array_slice($xs, 1); }
function foldl (callable $f) {
return function ($acc) use ($f) {
return function ($xs) use ($f, $acc) {
if (empty($xs))
return $acc;
else
return foldl ($f) (call_user_func($f, $acc, head($xs))) (tail ($xs));
};
};
}
function map (callable $f) {
return foldl (function ($acc, $x) use ($f) {
return array_merge($acc, [call_user_func($f, $x)]);
}) ([]);
}
function sum ($xs) {
return foldl (function ($x, $y) { return $x + $y; }) (0) ($xs);
}
function prop ($k) {
return function ($arr) use ($k) {
return $arr[$k];
};
};
function group_by (callable $f) {
return foldl (function ($acc, $x) use ($f) {
$key = call_user_func($f, $x);
if (array_key_exists($key, $acc))
array_push($acc[$key], $x);
else
$acc[$key] = [$x];
return $acc;
}) ([]);
}
function comp (callable $f) {
return function (callable $g) use ($f) {
return function ($x) use ($f, $g) {
return call_user_func($f, call_user_func($g, $x));
};
};
}
Put it all together and here's what you get
$result = $sumOrdersByHash($data);
echo json_encode($result, JSON_PRETTY_PRINT), PHP_EOL;
// =>
[
{
"hash": "1234WEDK",
"sum": 1100
},
{
"hash": "1234ABCD",
"sum": 200
}
]