LoginSignup
2
1

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-06-25

はじめに

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

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

やっていること

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

このやり方にした理由

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

最後に

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

参考資料

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1