【Laravel】コレクションとメソッド

#環境
PHP 7.3.24
Laravel 6.20.30
MAMP

#コレクションとは
・Laravel独自の配列を拡張したもの
・Eloquentクエリの結果(モデルからデータを取得した結果)は、コレクションインスタンスを返す
・メソッドチェーンで記述が可能
・コレクション型専用の関数が多数存在する

#コレクションメソッド７選
###map()
`map()`はコレクション型に入っているデータ全体に特定の処理や操作を行いたい場合に使用します。

下記の例は`$users`はキーに名前バリューに年齢が入ったコレクション型の連想配列です。
この連想配列のデータすべてに同様の処理（〇〇さんの年齢は××歳です。）を行っていきます。

```php
<?php

namespace App\Http\Controllers;

class ProductController extends Controller
{
    public function index() {
      // 名前と年齢（コレクション型）
      $users = collect(["佐藤"=>21, "鈴木"=>16, "宮本"=>22, "山﨑"=>26]);

      // 税込み価格をmapメソッドで計算
      $show_users = $users->map(function ($item, $key){
          echo $key ."さんの年齢は" .$item ."歳です。";
      });

      //　表示確認
      $show_users; 
      //佐藤さんの年齢は21歳です。鈴木さんの年齢は16歳です。宮本さんの年齢は22歳です。山﨑さんの年齢は26歳です。
    }
}
```

###filter()
`filter()`は必要なデータを取得することができるメソッドです。if文を書かなくても条件に適するデータを取ってくることができます。`filter()`はデータを取ってくるだけになるので、データの中身を編集して表示させることはできません。

下記の例では、名前と性別が入っているデータの中から、女性（female）のデータを取得します。

```php
<?php

namespace App\Http\Controllers;

class CollectionController extends Controller
{
    public function index()
    {
        // 名前と性別（コレクション型）
        $users = collect([
            ['name' => '山田', 'gender' => 'male'],
            ['name' => '田中', 'gender' => 'female'],
            ['name' => '葉山', 'gender' => 'female'],
            ['name' => '木下', 'gender' => 'male'],
            ['name' => '丸井', 'gender' => 'male'],
            ['name' => '桜木', 'gender' => 'female'],
        ]);

        // 女性のデータのみを取得
        $female = $users->filter(function ($item, $key) {
            return $item['gender'] === 'female';
        });

        // ブラウザで確認
        dd($female);
    }
}
```

```php:実行結果
Illuminate\Support\Collection {#384 ▼
  #items: array:3 [▼
    1 => array:2 [▼
      "name" => "田中"
      "gender" => "female"
    ]
    2 => array:2 [▼
      "name" => "葉山"
      "gender" => "female"
    ]
    5 => array:2 [▼
      "name" => "桜木"
      "gender" => "female"
    ]
  ]
}
```

###chunk()
`chunk()`はデータの数を分割するメソッドです。
例えば１０個のデータを４つずつに分けることができます。
下記の例ではデータの分割数に応じて画面に表示する列の数を決めるようなコードを書きました。
今回はviewファイル(bladeファイル)に直接PHPの記述をしています。

```php
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>chunkメソッドのテスト</title>
</head>

<body>
    {{-- コレクション型データの設定 --}}
    <?php
    $products = collect([
        ['product' => 'フレアシャツ', 'price' => 3000], 
        ['product' => 'ストレートパンツ', 'price' => 5500], 
        ['product' => 'マーメイドスカート', 'price' => 8700], 
        ['product' => 'セットアップ', 'price' => 12500], 
        ['product' => 'かごバック', 'price' => 3400],
        ['product' => 'ハイカットスニーカー', 'price' => 7000], 
        ['product' => 'タイトスカート', 'price' => 4500], 
        ['product' => 'Aラインワンピース', 'price' => 8900], 
        ['product' => 'ハイウエストジーンズ', 'price' => 14000], 
        ['product' => 'ローファー', 'price' => 2200]
    ]);
    
    // ここでchunk()の数字によって何列で表示するかを決める（今回は４列表示）
    $chunk_products = $products->chunk(4)->toArray();
    ?>

    <!-- $chunk_productsを$itemsに格納してループさせる(ここで４列分割になる) -->
    @foreach($chunk_products as $items)
    <ul>
        <!-- $itemsをループさせて商品ごとのデータを取得できるようにする -->
        @foreach($items as $item) 
        <li>
            <p>{{ $item['product'] }}</p>
            <p>{{ $item['price'] }}円</p>
        </li>
        @endforeach
    </ul>
    @endforeach
</body>
</html>

<style>
    * {
        list-style: none;
        text-align: center;
    }

    ul {
       display: flex;
    }

    li {
        border: 1px solid #000;
        width: 300px;
        height: 150px;
    }

</style>

```

実行結果
![スクリーンショット 2021-07-22 18.03.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916260/9be45395-4f35-2a92-3f37-f6a9bc7b699a.png)

###pluck()
`pluck()`は指定したキーのバリューだけを取得することができます。
連想配列にしたい場合は、第２引数にキーにしたいものを指定します。

```php
<?php

namespace App\Http\Controllers;

class CollectionController extends Controller
{
    public function index()
    {
        // ユーザーIDと名前（コレクション型）
        $users = collect([
            ['user_id' => 1, 'name' => "モモカ"], 
            ['user_id' => 2, 'name' => "ミズキ"], 
            ['user_id' => 3, 'name' => "レオン"], 
            ['user_id' => 4, 'name' => "シュン"], 
        ]);

        // キーにユーザーID、バリューに名前をもつ連想配列としてデータを取得
        $user_list = $users->pluck('name', 'user_id');
        dd($user_list);
    }
}

```

実行結果

```php
Illuminate\Support\Collection {#383 ▼
  #items: array:4 [▼
    1 => "モモカ"
    2 => "ミズキ"
    3 => "レオン"
    4 => "シュン"
  ]
}
```

###dd()
`dd()`は処理を中断してデータの中身を表示できるメソッドです。
ヘルパ関数の`dd()`はデバッグでよく使っていましたが、コレクションのメソッドでもあるのは初めて知りました。
メソッドチェーンの間に`->dd()`を記述することで途中経過のデータの中身を確認することができます。

下記の例では`map()`で３段階で数値を足していく処理の途中で`dd()`を使って確認してみました。

```php
<?php

namespace App\Http\Controllers;

class CollectionController extends Controller
{
    public function index()
    {
        $number = collect([10, 22, 14, 55, 89])

        // $numberにそれぞれ10ずつ足す
        ->map(function ($item, $key){
            $item += 10;
            return $item;
        })
        // ここで一旦処理を中断して中身を表示
        ->dd()
        // さらに20足す
        ->map(function ($item, $key){
            $item += 20;
            return $item;
        })
        // さらにさらに30足す
        ->map(function ($item, $key){
            $item += 30;
            return $item;
        });

        echo $number; //[70,82,74,115,149]
        
    }
}
```

メソッドチェーンの間に書いた`->dd()`でのブラウザの表示結果は以下のようになりました。
問題なく計算途中の数値が表示されています。

```php
Illuminate\Support\Collection {#384 ▼
  #items: array:5 [▼
    0 => 20
    1 => 32
    2 => 24
    3 => 65
    4 => 99
  ]
}
```

###has()
`has()`は指定したキーがコレクションの中に存在しているかどうかを調べることができます。
メソッドの実行結果は、trueまたはfalseを返します。

```php
<?php

namespace App\Http\Controllers;

class CollectionController extends Controller
{
    public function index()
    {
        // ユーザー情報（コレクション型）
        $users = collect(['id' => 15, 'name' => "田中", 'age' => 28, 'hobby' => "ピアノ"]);

        dd($users->has('hobby'));  //true
        dd($users->has('gender')); //false
        dd($users->has('name'));   //true
    }
}
```

###toArray()
`toArray()`は型をコレクションから配列へと変換するメソッドです。
`dd()`で確認すると、`toArray()`を使うことでコレクション型でなくなっていることがすぐに分かります。

```php
<?php

namespace App\Http\Controllers;

class CollectionController extends Controller
{
    public function index()
    {
        // ユーザー情報（コレクション型）
        $users = collect(['id' => 15, 'name' => "田中", 'age' => 28, 'hobby' => "ピアノ"]);

        // コレクション型
        dd($users);
        /* 
        Illuminate\Support\Collection {#366 ▼
            #items: array:4 [▼
            "id" => 15
            "name" => "田中"
            "age" => 28
            "hobby" => "ピアノ"
            ]
        }  
        */

        // 配列型に変換
        dd($users->toArray());
        /*
        array:4 [▼
        "id" => 15
        "name" => "田中"
        "age" => 28
        "hobby" => "ピアノ"
        ]
        */
    }
}
```

#コレクションの注意点
コレクションはデータが大量に入っているため、配列と比べて処理速度が遅くなります。
パフォーマンスが要求される場合は<font color="red">配列に変換して処理を行う方が処理速度が上がる</font>ので、場合に応じてコレクションで処理するか配列に変換して処理するかを判断する必要があります。

#参考
[公式マニュアル](https://readouble.com/laravel/5.8/ja/collections.html)
[全117種類！Laravel 5.6〜7.xのコレクション実例](https://blog.capilano-fw.com/?p=493#map)