PHP
Laravel

Laravelコレクションメソッド groupByを重ねて複数使うには? (練習問題形式)


はじめに

Laravelのコレクションの便利なメソッドgroupBy

あれこれ触ったので、覚えたことを忘れないよう、練習問題にしてみました。

タイトルの、groupByを重ねて複数使う、最後の問3です。

すぐにやり方を知りたいという方はこちらへどうぞ。


問題

Order, OrderDetail, Book, Publisherモデルがあり、OrderDetailからリレーションのあるBook, Publisherまでを以下のように取得しました。

$order_details = OrderDetail::with('book.publisher')->get();

print_r(json_encode($order_details, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT))


$order_detailsをJSON化したもの

[

{
"id": 10001,
"order_id": 1,
"book_id": 111,
"selling_price": 3000,
"book": {
"id": 111,
"publisher_id": 11,
"name": "自習Laravel",
"list_price": 3500,
"is_electronic_book": false,
"publisher": {
"id": 11,
"name": "AA出版"
}
}
},
{
"id": 10002,
"order_id": 1,
"book_id": 222,
"selling_price": 2500,
"book": {
"id": 222,
"publisher_id": 22,
"name": "基礎から学ぶPHP",
"list_price": 3000,
"is_electronic_book": true,
"publisher": {
"id": 22,
"name": "BB出版"
}
}
},
{
"id": 10003,
"order_id": 1,
"book_id": 333,
"selling_price": 3000,
"book": {
"id": 333,
"publisher_id": 22,
"name": "パーフェクトLaravel",
"list_price": 3000,
"is_electronic_book": false,
"publisher": {
"id": 22,
"name": "BB出版"
}
}
}
]


問1

publisher_idgroupByしてください。


問2

問1の結果では、グループ化された配列のキーはpublisher_idの値になります。(1122)

{

"11": [
{
"id": 10001,
"order_id": 1,
"book_id": 111,
"selling_price": 3000,
"book": {
"id": 111,
"publisher_id": 11,
"name": "自習Laravel",
"list_price": 3500,
"is_electronic_book": false,
"publisher": {
"id": 11,
"name": "AA出版"
}
}
}
],
"22": [
{
"id": 10002,
"order_id": 1,
"book_id": 222,
//略

これを0から振り直してください。(JSON化した場合、以下のように出力されるようにしてください)

[

[
{
"id": 10001,
"order_id": 1,
"book_id": 111,
"selling_price": 3000,
"book": {
"id": 111,
"publisher_id": 11,
"name": "自習Laravel",
"list_price": 3500,
"is_electronic_book": false,
"publisher": {
"id": 11,
"name": "AA出版"
}
}
}
],
[
{
"id": 10002,
"order_id": 1,
"book_id": 222,
//略


問3

まず、is_electronic_bookgroupByし、その上でそれぞれの要素に対して、publisher_idgroupByしてください。


補足

必要に応じてLaravel公式ドキュメントのgroupByほかを参照してください。

https://readouble.com/laravel/5.8/ja/collections.html#method-groupby

ここから先、解答になります。

...

...

...


解答


問1の解答


publisher_idgroupByしてください。


publisher_idは、bookをキーとする値の中に、さらにキーとして存在していました。


$order_detailsをJSON化したものの抜粋

        "book": {

"id": 111,
"publisher_id": 11,

こういった場合は、.で繋いで指定すればOKです。


問1の解答例

$answer1 = $order_details->groupBy('book.publisher_id');



問1の別解

$answer1 = $order_details->groupBy('book.publisher.id');



問2の解答


問1の結果では、グループ化された配列のキーはpublisher_idの値になります。(1122)

これを0から振り直してください。


キーの振り直しにはコレクションのメソッドであるvaluesが使えます。


valuesメソッドはキーをリセット後、連続した整数にした新しいコレクションを返します。

Laravel5.8 公式ドキュメント - values

https://readouble.com/laravel/5.8/ja/collections.html#method-values



問2の解答例

$answer2 = $order_details->groupBy('book.publisher_id')

->values();


問2の解答例の結果をJSON化したもの

[

[
{
"id": 10001,
"order_id": 1,
"book_id": 111,
"selling_price": 3000,
"book": {
"id": 111,
"publisher_id": 11,
"name": "自習Laravel",
"list_price": 3500,
"is_electronic_book": false,
"publisher": {
"id": 11,
"name": "AA出版"
}
}
}
],
[
{
"id": 10002,
"order_id": 1,
"book_id": 222,
"selling_price": 2500,
"book": {
"id": 222,
"publisher_id": 22,
"name": "基礎から学ぶPHP",
"list_price": 3000,
"is_electronic_book": true,
"publisher": {
"id": 22,
"name": "BB出版"
}
}
},
{
"id": 10003,
"order_id": 1,
"book_id": 333,
"selling_price": 3000,
"book": {
"id": 333,
"publisher_id": 22,
"name": "パーフェクトLaravel",
"list_price": 3000,
"is_electronic_book": false,
"publisher": {
"id": 22,
"name": "BB出版"
}
}
}
]
]


問3の解答

groupByを重ねて複数使うには、同じくコレクションのメソッドであるtransformも利用することが考えられます。


問3の解答例

$answer3 = $order_details->groupBy('book.is_electronic_book')

->transform(function ($order_detail) {
return $order_detail->groupBy('book.publisher_id')
->values(); // valuesは用途に応じてお好みで。詳細は問2参照。
});


transformメソッドはコレクションを繰り返し処理し、コレクションの各アイテムに指定したコールバックを適用します。コレクション中のアイテムはコールバックから返される値に置き換わります。

Laravel5.8 公式ドキュメント - transform

https://readouble.com/laravel/5.8/ja/collections.html#method-transform


解答例ではis_electronic_bookgroupByした結果、2つの要素に分かれていますので、このtransformを使って各々の要素に対してさらにpublisher_idgroupByしています。


問3の解答例の結果をJSON化したもの

[

[
[
{
"id": 10001,
"order_id": 1,
"book_id": 111,
"selling_price": 3000,
"book": {
"id": 111,
"publisher_id": 11,
"name": "自習Laravel",
"list_price": 3500,
"is_electronic_book": false,
"publisher": {
"id": 11,
"name": "AA出版"
}
}
}
],
[
{
"id": 10003,
"order_id": 1,
"book_id": 333,
"selling_price": 3000,
"book": {
"id": 333,
"publisher_id": 22,
"name": "パーフェクトLaravel",
"list_price": 3000,
"is_electronic_book": false,
"publisher": {
"id": 22,
"name": "BB出版"
}
}
}
]
],
[
[
{
"id": 10002,
"order_id": 1,
"book_id": 222,
"selling_price": 2500,
"book": {
"id": 222,
"publisher_id": 22,
"name": "基礎から学ぶPHP",
"list_price": 3000,
"is_electronic_book": true,
"publisher": {
"id": 22,
"name": "BB出版"
}
}
}
]
]
]


最後に

以上です。何問解けたでしょうか?

コレクションメソッドを使っていて、また何か気付きがあれば練習問題にしてみたいと思います:innocent:


参考