Laravel中如何用calebporzio/sushi插件从其他表动态填充数据?
问题原因与解决步骤
问题出在Sushi的默认机制:直接设置$rows属性属于静态预设数据,只会在模型首次加载时生效,不会动态更新。要实现运行时从数据库拉取最新数据,必须通过重写getRows()方法来动态生成数据集,同时结合Filament Tree的需求构建树结构。
1. 修正TaskTicketReport模型的Sushi配置
移除静态$rows属性,重写getRows()方法,让模型每次查询时都动态拉取Task、Tickets、Ticket_user的关联数据并构造成树节点格式:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Sushi\Sushi; use App\Models\Task; use App\Models\Ticket; class TaskTicketReport extends Model { use Sushi; // 关闭Sushi缓存,确保每次都拉取最新数据(按需开启) public $cache = false; /** * 动态生成树结构所需的数据集 */ public function getRows() { // 1. 拉取活跃任务作为树的根节点,关联工单数量和关联用户总数 $taskNodes = Task::where('is_active', true) ->withCount([ 'tickets', 'tickets as assigned_user_total' => function ($query) { $query->select(\DB::raw('COUNT(DISTINCT ticket_user.user_id)')) ->join('ticket_user', 'tickets.id', '=', 'ticket_user.ticket_id'); } ]) ->get() ->map(function ($task) { return [ 'id' => 'task_' . $task->id, // 加前缀避免与工单ID冲突 'name' => $task->name, 'parent_id' => null, // 任务作为根节点 'ticket_count' => $task->tickets_count, 'user_count' => $task->assigned_user_total, 'node_type' => 'task', // 标记节点类型,方便Filament区分展示 ]; }); // 2. 拉取关联工单作为任务节点的子节点,关联该工单的用户数 $ticketNodes = Ticket::whereHas('task', fn($q) => $q->where('is_active', true)) ->withCount('users') ->get() ->map(function ($ticket) { return [ 'id' => 'ticket_' . $ticket->id, 'name' => $ticket->title, 'parent_id' => 'task_' . $ticket->task_id, // 关联到对应任务节点 'user_count' => $ticket->users_count, 'node_type' => 'ticket', ]; }); // 合并任务和工单节点,返回树结构数据集 return $taskNodes->concat($ticketNodes)->toArray(); } }
2. 配置Filament Tree资源
确保Filament Tree资源正确绑定模型,并根据节点类型配置展示字段:
<?php namespace App\Filament\Resources; use App\Models\TaskTicketReport; use Filament\Tables; use SolutionForest\FilamentTree\Resources\Concern\HasTree; use Filament\Resources\Resource; class TaskTicketReportResource extends Resource { use HasTree; protected static ?string $model = TaskTicketReport::class; protected static ?string $navigationIcon = 'heroicon-o-folder-tree'; public static function treeSchema(): array { return [ Tables\Columns\TextColumn::make('name') ->label('节点名称') ->sortable(), Tables\Columns\TextColumn::make('ticket_count') ->label('关联工单数') ->visible(fn($record) => $record['node_type'] === 'task'), Tables\Columns\TextColumn::make('user_count') ->label('关联用户数'), ]; } // 按需补充表单、权限等其他配置 }
3. 验证与调试
- 用Artisan Tinker验证模型数据是否正确:
php artisan tinker >>> App\Models\TaskTicketReport::all();
- 如果仍存在缓存问题,可手动清除Sushi缓存:
TaskTicketReport::flushCache();
内容的提问来源于stack exchange,提问作者Petro Gromovo
相关产品推荐
相关产品推荐

