Given the following data:
manufacturers makes
id | name id | manufacturer_id | name
---|----- -- | --------------- | ----
1 | Honda 1 | 1 | Honda
2 | Toyota 2 | 1 | Acura
3 | Mazda 3 | 2 | Toyota
4 | Other 4 | 2 | Lexus
5 | 3 | Mazda
6 | 4 | Other
I'm trying to get an array that looks like this:
[
"Honda" => [1 => "Honda", 2 => "Acura"],
"Toyota" => [3 => "Toyota", 4 => "Lexus"],
5 => "Mazda",
6 => "Other",
]
In other words, group by manufacturer, but only if the manufacturer has more than one make. The method for specifying this condition is eluding me. So far I've got this:
Make::with("manufacturer")
->get()
->groupBy(
fn (Make $m) => $m->manufacturer->models->count() < 2 ? null : $m->manufacturer->name
)
->map(
fn (Collection $c) => $c->mapWithKeys(
fn (Make $m) => [$m->id => $m->name]
)
)
->toArray();
I had hoped returning null
from the groupBy
callback would prevent the grouping, but no such luck. It gives me this:
[
"" => [5 => "Mazda", 6 => "Other"]
"Honda" => [1 => "Honda", 2 => "Acura"],
"Toyota" => [3 => "Toyota", 4 => "Lexus"],
]
So I want a way to either conditionally group in the first place, or conditionally flatten after the grouping. I know I can do the latter manually, but it seems like something there should be a built-in Collection method for doing.
You can use
$result = Make::with('manufacturer')->get()
->groupBy('manufacturer.name')
->flatMap(function ($makes, $manufacturerName) {
if ($makes->count() > 1) {
return [$manufacturerName => $makes->pluck('name', 'id')];
}
$make = $makes->first();
return [$make->id => $make->name];
})
->toArray();
groupBy('manufacturer.name')
group by manufacturer name.
flatMap
used to check if each manufacturer has more than one make