记一次通过 Resource 递归生成树的方案

数据库结构

记一次通过Resource递归生成树的方案

Model:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Menu extend Model {
    protected $table = 'menus';
    protected $fillable = ['name'];
    public function children()
    {
        return $this->hasMany(Menu::class, 'parent_id');
    }
    public function scopeParents($query)
    {
        return $query->where('depth', 0);
    }
}

Resource:

namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class TreeResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'parentId' => $this->parent_id,
            'name' => $this->name,
            'children' => TreeResource::collection(
                $this->children->load(['children' => function ($query) {
                    return $query->orderBy('sorter', 'asc');
                }])
            ),
        ];
    }
}

Controller:

namespace App\Http\Controllers;
use App\Http\Resources\TreeResource;
use App\Menu;
use Illuminate\Http\Request;
class StoreGroupController extends Controller
{
    public function tree()
    {
        $parents = Menu::with([
            'children' => function ($query) {
                return $query->orderBy('sorter', 'asc'); // 排序
            }])->parents()->orderBy('sorter', 'asc')->get();
        return TreeResource::collection($parents);
    }
}

采用load()减少每次递归时候的查询量

可在闭包中添加排序规则

本作品采用《CC 协议》,转载必须注明作者和本文链接
打酱油
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 4

这样不是在循环查数据库吗?为什么不能全部取出来在组装数据,,这样不就一条sql就搞定了?

4年前 评论
sureyee (楼主) 4年前

示例代码 明白意思就行,修改下就能用了,不用多次查询

        $routers = $routers->keyBy('id');   // 以ID 为键值

        foreach ($routers as $id => $router) {
            //    $parent 当前循环的 $router的父级
            if ($router->parent_id && $parent = $routers->get($router->parent_id)) {
                if (!$parent->relationLoaded('children')) {
                    $parent->setRelation('children', new Collection());
                }

                $parent->getRelation('children')->push($router);
            }
        }
        $result = $routers->groupBy('parent_id')->get(0);
4年前 评论
 public function toArray($request)     {         return [             'name'=>$this->name,             'code'=>$this->code,             'children' => $this->when($this->children->count()>0,                 DepartmentResource::collection(                     $this->children->load(['children'=> function ($query) {                         return $query->orderBy('sorter', 'asc');                     }])                 )             )         ];     }

使用了条件加载。当children不为空时才返回后代数据。不知这样是否可行

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!