経路列挙モデルをJSON形式の木構造にする

##はじめに
今回、経路列挙モデルでデータベースに格納したデータをプログラムで扱いやすい構造に作り変えます。

Vue.jsで遊ぶことが多いのでフロント側でも扱いやすいJSONにしたいと思います。

実装したコードの一部分にLaravelの機能があります。

##注意
Laravelの学習中に遭遇した課題であり、調べてもあまり記事が見つからなかったのでとりあえずメモ的なものとして投稿しております。
そのため雑な紹介となっています。
Laravelを使っていないソースに書き直すことはおそらくないと思います。
ご了承お願いします。

##準備
|    | バージョン |  
|:-----------|------------:|
| Laravel    |  7.2.0  |
| PHP     | 7.2.15 |
| MySQL    | 8.0.16 |


##データの内容
```

+----+--------------------+---------+---------------------+---------------------+
| id | name               | path    | created_at          | updated_at          |
+----+--------------------+---------+---------------------+---------------------+
|  1 | book               | /1/     | 2020-04-18 07:47:57 | 2020-04-18 07:47:57 |
|  2 | novel              | /1/2/   | 2020-04-18 07:47:57 | 2020-04-18 07:47:57 |
|  3 | comic              | /1/3/   | 2020-04-18 07:47:57 | 2020-04-18 07:47:57 |
|  4 | musical instrument | /4/     | 2020-04-18 07:47:57 | 2020-04-18 07:47:57 |
|  5 | piano              | /4/5/   | 2020-04-18 07:47:57 | 2020-04-18 07:47:57 |
|  6 | grand piano        | /4/5/6/ | 2020-04-18 07:47:57 | 2020-04-18 07:47:57 |
+----+--------------------+---------+---------------------+---------------------+
```

今回使用するカテゴリーのデータです。


##木構造にするソースコード(抜粋)
```ItemCategoryService.php
  public function getAll()
  {
    $data = $this->item_category_rep->readAll();
     //readAll()でカテゴリーの全データを取得。
     //(Laravel)$this->カテゴリーのモデル->all()
     //をしているだけ。
    return $this->convertToTreeStructure($data);
  }
  
  public function convertToTreeStructure($rows)
  {
    $result = [];
    foreach ($rows as $row) {
      $path = $row->path;
      $route_array = array_filter(explode("/", $path));
      $temp = [];

      foreach(array_reverse($route_array)  as $i => $node_id) {
        $temp = [
          'id' => $rows->find($node_id)->id,
          'name' => $rows->find($node_id)->name,
          'path' => $rows->find($node_id)->path,
          'children' => $i === 0 ? [] : [$temp]
        ];
      }
      $this->merge($result, $temp);
    }
    return $result;
  }

  public function merge(&$current, $branch, $node='root')
  {
    if ($node === 'child') {
      $key = array_search($branch['id'], array_column($current['children'], 'id'));
      if ($key === false) {
        array_push($current['children'], $branch);
      } else {
        $this->merge($current['children'][$key], $branch['children'][0], 'child');
      }
    } else if ($node === 'root') {
      $key = array_search($branch['id'], array_column($current, 'id'));
      if ($key === false) {
        array_push($current, $branch);
      } else {
        $this->merge($current[$key], $branch['children'][0], 'child');
      }
    }
  }
  ```
##出力(抜粋)
```output.php
public function index()
    {
        $data = $this->itemCategoryService->getAll();
        echo "<pre>";
        echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT );
        echo "</pre>";
    }
```
##出力結果
![Screen Shot 2020-04-18 at 17.14.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454133/04795a0f-5460-8bca-df26-6012f794408f.png)

##やっていること
1. それぞれの単体カテゴリーのrootからのpathを構造化
2. それらを一つに結合する(イメージとしてはGitのmerge)

##このやり方にした理由
データベースに格納したデータについてで、
万が一、子のカテゴリーのIDが親より古いIDを持っていいた場合に対処するため。

##最後に
ご教授コメント欄でお願いします。

##参考資料
http://mao1020.hateblo.jp/entry/20140127/1390808003