如何使用闭包表遍历树结构以便在 Eloquent 模型中创建 json?

问题描述 投票:0回答:1

在我的应用程序中,我有下表:

CREATE TABLE files (
    id bigint IDENTITY(1,1) NOT NULL,
    name nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    folder bigint NULL,
    [type] nvarchar(10) NOT NULL CHECK ([type] IN ('FILE', 'FOLDER')) DEFAULT 'FOLDER',
    CONSTRAINT PK__3213E83FDB19A582 PRIMARY KEY (id),
    CONSTRAINT folder_fk FOREIGN KEY (folder) REFERENCES files(id),
);

create table files_closure (
    ancestor bigint NOT NULL,
    decedant bigint NOT NULL,
    "depth" int NOT NULL,
    CONSTRAINT files_closure_pk PRIMARY KEY (ancestor,decedant),
    CONSTRAINT files_closure_ancestor_fk FOREIGN KEY (ancestor) REFERENCES files(id),
    CONSTRAINT files_closure_decedant_fk FOREIGN KEY (decedant) REFERENCES files(id),
);

每个桌子也有自己的模型:

文件

class Files extends Model
{
  protected $table='files';
  public $timestamps = false;
  
  public function parentFolder():HasOne
  {
     return $this->hasOne(self::class,'id','folder');
  }

  public function files(): HasMany
  {
    return $this->hasMany(self::class, 'folder');
  }
}

对于关闭表:

class FilesClosure extends Model
{
  protected $table='files_closure';
  public $timestamps = false;
  
  public function ancestor():HasOne
  {
     return $this->hasOne(Files::class,'ancestor','id');
  }

  
  public function decedant():HasOne
  {
     return $this->hasOne(Files::class,'ancestor','id');
  }
}

我想尽可能快地创建一个json结构(在最少的执行时间内而不造成数据库开销):

{
  files: [
      {
        name:"My Music",
        type: "FOLDER",
        files: [
           {
             name: "Halford",
             type: "FOLDER",
             files: [
               {
                 name: "Locked-and-loaded.mp3",
                 type: "FILE"
               },
               {
                 name: "Another Song.mp3",
                 type: "FILE"
               }
             ]
           }
        ]
      }
  ]
}

如果我避免使用闭包表,我可以将数据检索为:

$json = Files::with('parentFolder','files')->whereNull('folder')->get()->toJson();

但这会导致多个查询,并且响应时间很慢,尤其是在大型数据集上。因此我想使用闭包表,但我不知道如何做到这一点。

php laravel eloquent transitive-closure-table
1个回答
0
投票

检查下面我修改了 Laravel

Files
模型以使用闭包表有效处理分层数据的位置。该方法涉及单个查询,该查询将
files
表与
files_closure
表连接起来以检索分层数据,同时尊重文件夹文件结构。然后在 PHP 中处理该数据以构建树状结构。
getHierarchicalData
模型中的静态方法
Files
获取数据,另一组方法
buildTree
buildBranch
用于将此数据组织成嵌套树格式,反映文件夹-文件层次结构。这种方法最大限度地减少了数据库查询次数,特别有利于大型数据集,并且最终的树结构转换为 JSON 格式,适合所需的输出。

class Files extends Model
{
    protected $table = 'files';
    public $timestamps = false;

    // New method to retrieve hierarchical data
    public static function getHierarchicalData()
    {
        // Get hierarchical data
        $data = DB::table('files as f')
            ->join('files_closure as fc', 'f.id', '=', 'fc.decedant')
            ->select('f.*', 'fc.ancestor', 'fc.depth')
            ->orderBy('fc.ancestor')
            ->orderBy('fc.depth')
            ->get();

        return self::buildTree($data);
    }

    protected static function buildTree($data)
    {
        $items = [];
        foreach ($data as $item) {
            $items[$item->ancestor][] = $item;
        }

        $tree = self::buildBranch($items, null);
        return $tree;
    }

    protected static function buildBranch(&$items, $parentId)
    {
        $branch = [];
        foreach ($items[$parentId] as $item) {
            if (isset($items[$item->id])) {
                $item->files = self::buildBranch($items, $item->id);
            } else {
                $item->files = [];
            }
            $branch[] = $item;
        }
        return $branch;
    }
}

在控制器中,您调用:

$json = json_encode(Files::getHierarchicalData());
© www.soinside.com 2019 - 2024. All rights reserved.