dd/app/Models/Nasa/Navigation.php
2026-07-04 19:01:35 +08:00

134 lines
4.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Models\Nasa;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Route;
class Navigation extends Model
{
protected $table = 'nasa_navigation';
protected $primaryKey = 'id';
const CREATED_AT = 'dtCreatedAt';
const UPDATED_AT = 'dtUpdatedAt';
const TYPE_TOP_BAR = 'TOP_BAR';
const TYPE_SIDEBAR_MENU = 'SIDEBAR_MENU';
const TYPE_INNER_PAGE_TAB = 'INNER_PAGE_TAB';
const STATUS_OPEN = 1;
const STATUS_CLOSE = 0;
private static array $aComponentLabels = [
self::TYPE_TOP_BAR => '顶部导航条',
self::TYPE_SIDEBAR_MENU => '侧边栏菜单',
self::TYPE_INNER_PAGE_TAB => '页面内标签页',
];
private static array $aStatusLabels = [
self::STATUS_OPEN => '开启',
self::STATUS_CLOSE => '关闭',
];
public function getMapAll()
{
$aMap = [
'sComponentType' => self::$aComponentLabels,
'iStatus' => self::$aStatusLabels
];
return $aMap;
}
protected function casts(): array
{
return [
'dtUpdatedAt' => 'datetime:Y-m-d H:i:s', // 自动转换为 Carbon 对象
'dtCreatedAt' => 'datetime:Y-m-d H:i:s', // 写入时自动 password_hash 加密
];
}
/**
* 递归获取当前菜单的所有上级祖先节点(包含自身)
* 结果按从根节点到当前节点的顺序排列(即:[一级, 二级, 三级, 当前]
*
* @return \Illuminate\Support\Collection
*/
public function cGetAncestorsAndSelf(): \Illuminate\Support\Collection
{
$cPath = collect([$this]);
$oCurrent = $this;
// 使用循环代替递归进行反向溯源,性能更佳,防止极端情况下的堆栈溢出
while ($oCurrent->iParentId != 0) {
// 高标准注意:这里如果能做内存缓存或走预加载更佳,但由于是单条数据向上,走主键查询性能损耗可控
$oParent = self::where('id', $oCurrent->iParentId)->available()->first();
if (!$oParent) {
break; // 防御性编程:万一数据链断了,及时跳出
}
$cPath->prepend($oParent); // 往前插入,保证顺序是 [父, 子, 孙]
$oCurrent = $oParent;
}
return $cPath;
}
public function children()
{
// 这里的 iParentId 是外键id 是当前表的主键
return $this->hasMany(self::class, 'iParentId', 'id');
}
/**
* 你的本地作用域Scope确保 scopeAvailable 存在
* 顺便提一句,高标准设计中,状态字段建议内聚在 scope 里
*/
public function scopeAvailable($query)
{
// 假设你的可用状态字段是 iStatus 且 1 为可用,请根据实际字段调整
return $query->where('iStatus', 1);
}
/**
* 高标准设计:递归预加载所有下级(无限级核心)
* 只要这一条 Eager LoadingLaravel 会自动用最少的 SQL 把整棵树一次性读入内存
*/
public function childrenRecursive()
{
return $this->children()
->available()
->orderBy('iSort', 'asc')
->with('childrenRecursive'); // 完美的自我套娃
}
/**
* 业务逻辑内聚:深度优先穿透获取最终 URL
* 职责:如果有下级,永远优先往下找第一个合法的下级;如果没有下级或下级全挂了,退回自身。
*/
public function sGetFinalUrl(): string
{
// 1. 如果有下级集合(已经过 available 过滤),尝试向下穿透
if ($this->relationLoaded('childrenRecursive') && $this->childrenRecursive->isNotEmpty()) {
foreach ($this->childrenRecursive as $oChild) {
// 递归向下寻找子节点的最终 URL
$sChildUrl = $oChild->sGetFinalUrl();
// 只要子节点或者孙子节点能返回一个有效 URL立刻中断并返回它最左原则
if (!empty($sChildUrl)) {
return $sChildUrl;
}
}
}
// 2. 兜底逻辑:没有下级,或者所有下级分支都没配置有效路由,返回自身的 URL
// return $this->sPermissionSlug;
return Route::has($this->sPermissionSlug) ? route($this->sPermissionSlug) : '';
}
}