format('Y-m-d H:i:s'); } protected static function boot() { parent::boot(); // 监听 Keyword 的创建事件,用于初始化 path 和 lv 字段值 static::saving(function (Keyword $keyword) { if (is_null($parent = $keyword->parent)) { $keyword->forceFill([ 'path' => '-', 'lv' => 1, ]); if ((string) $keyword->key === '') { $keyword->key = Str::random(16); } } else { $keyword->forceFill([ 'parent_key' => $parent->lv > 1 ? $parent->parent_key : $parent->key, 'path' => $parent->full_path, 'lv' => $parent->lv + 1, ]); if ((string) $keyword->key === '') { $keyword->key = $parent->key.'_'.($parent->children()->count() + 1); } } }); } public function parent() { return $this->belongsTo(static::class, 'parent_id'); } public function children() { return $this->hasMany(static::class, 'parent_id'); } public function scopeSort($q) { return $q->orderBy('sort', 'asc'); } public function scopeAllChildrenOfKey($q, $parentKey) { $q->where('path', 'like', '%-'. static::where('key', $parentKey)->value('id') .'-%' ?? ''); } public static function tagsMap(string $key) { $mapArr = []; self::query()->where('parent_key', $key)->get()->map(function ($item) use (&$mapArr) { $mapArr[$item->id] = Components::make()->keywordsTag($item->name, $item->value); }); return $mapArr; } protected function fullPath(): Attribute { return Attribute::make( get: fn (mixed $value, array $attributes) => $attributes['path'].$attributes['id'].'-', ); } }