You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 8中如何让模型属性依不同仓库方法返回不同结果

解决Laravel模型属性根据仓库方法返回不同结果的问题

方法一:给模型添加临时状态标记

通过在模型上设置临时属性,让仓库方法可以控制children属性的返回逻辑:

  1. 修改模型代码
    添加一个公共标记属性,调整getChildrenAttribute的判断逻辑:
public $timestamps = false;
protected $guarded = ['Id'];
protected $table = 'MapLayerGroup';

protected $appends = ['leaf', 'children'];
protected $hidden = ['descendants', 'mapLayers'];

// 新增临时标记,控制是否包含mapLayers
public $includeMapLayers = false;

public function parent()
{
    return $this->belongsTo(MapLayerGroupModel::class, 'ParentId');
}

public function descendants()
{
    return $this->hasMany(MapLayerGroupModel::class, 'ParentId')->orderBy('id', 'asc');
}

public function mapLayers()
{
    return $this->hasMany(MapLayerModel::class, 'MapLayerGroupId', 'Id');
}

public function getChildrenAttribute()
{
    if (!$this->includeMapLayers) {
        return $this->descendants->toArray();
    } else {
        return array_merge(
            $this->descendants->toArray(),
            $this->mapLayers->toArray()
        );
    }
}

public function getLeafAttribute()
{
    return count($this->children) === 0;
}
  1. 修改仓库方法
    在返回结果前,遍历模型实例设置标记:
public function paginate(array $options = [])
{
    $typeCode = $options['typeCode'] ?? null;

    $user = Auth::user();
    $is_admin = $user->isAdmin();

    if(!$is_admin && $typeCode === null) {
        throw BaseException::withMessages([
            __('Gis::error.map_layer.not_allowed')
        ]);
    }

    $query = $this->model
        ->whereNull('ParentId')
        ->with(['descendants'])
        ->orderBy('Id', 'asc');
    if ($typeCode !== null) {
        $query->whereHas('MapLayerGroupType', function ($query) use ($typeCode) {
            $query->where('Code', $typeCode);
        });
    }

    $this->setQuery($query);

    $result = parent::paginate($options);
    // 设置标记:不包含mapLayers
    foreach ($result->items() as $item) {
        $item->includeMapLayers = false;
    }
    return $result;
}

public function mapGroupLayersList()
{
    $query = $this->model
        ->with(['descendants', 'mapLayers']) // 预加载mapLayers避免N+1查询
        ->whereNull('ParentId')
        ->orderBy('Id', 'asc');

    $this->setQuery($query);

    $result = parent::paginate();
    // 设置标记:包含mapLayers
    foreach ($result->items() as $item) {
        $item->includeMapLayers = true;
    }
    return $result;
}

方法二:使用API资源类(更优雅的方案)

通过Laravel的API资源类,根据不同场景返回不同结构,无需修改模型核心逻辑:

  1. 创建资源类
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class MapLayerGroupResource extends JsonResource
{
    private $includeMapLayers;

    public function __construct($resource, $includeMapLayers = false)
    {
        parent::__construct($resource);
        $this->includeMapLayers = $includeMapLayers;
    }

    public function toArray($request)
    {
        $children = $this->descendants->toArray();
        if ($this->includeMapLayers) {
            $children = array_merge($children, $this->mapLayers->toArray());
        }

        return [
            'id' => $this->Id,
            // 其他需要返回的字段
            'children' => $children,
            'leaf' => count($children) === 0,
        ];
    }
}
  1. 仓库方法中使用资源返回
public function paginate(array $options = [])
{
    // 原有查询逻辑...

    $result = parent::paginate($options);
    // 默认不包含mapLayers
    return MapLayerGroupResource::collection($result);
}

public function mapGroupLayersList()
{
    $query = $this->model
        ->with(['descendants', 'mapLayers'])
        ->whereNull('ParentId')
        ->orderBy('Id', 'asc');

    $this->setQuery($query);

    $result = parent::paginate();
    // 传入true表示包含mapLayers
    return MapLayerGroupResource::collection($result, true);
}

内容的提问来源于stack exchange,提问作者Shokouh Dareshiri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 23:13:12