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

Laravel10中belongsTo关联select时附加属性无法生成的问题

问题描述

模型定义

User模型

protected $appends = [
        'full_name',
        'avatar',
    ];

    public function company(): HasOne
    {
        return $this->hasOne(Company::class);
    }

/**
     * 返回用户照片可访问URL的获取器
     *
     * @return Attribute
     */
    public function avatar(): Attribute
    {
        return Attribute::make(
            get: static function (?string $value, array $attributes) {

                asset(str_replace('public', 'storage', self::$avatarPath)
                    . '_' .
                    $attributes['full_name'] . '_' . $attributes['id'] . '.webp'
                );
            },
        );
    }

public function fullName(): Attribute
    {
        return new Attribute(
            get: fn () => $this->first_name .' ' . $this->last_name
        );
    }

Company模型

public function user(): BelongsTo
{
    return $this->belongsTo(User::class);
}

查询代码

public static function adminTableData(): Builder
    {
        return self::query()->with(['user' => function($query) {
            $query->select('id', 'first_name', 'last_name');
    }])->paginate(10)->toJson();
    }

错误信息

Undefined array key "full_name"

错误出现在User模型的avatar方法中:

$attributes['full_name'] . '_' . $attributes['id'] . '.webp'
问题原因与解决方案

核心原因

  • $attributes只存数据库字段:full_name是你通过$appends添加的附加属性,不属于数据库表字段,所以不会出现在$attributes数组里,直接读取自然报错。
  • 静态获取器无法访问模型实例:avatar的get闭包用了static修饰,导致无法通过$this访问模型实例,而full_name依赖模型的first_name和last_name生成,静态环境下拿不到这个附加属性的值。

修复方案

方案1:去掉static,直接调用模型的full_name属性

修改avatar获取器,去掉static,用$this->full_name代替$attributes['full_name'],同时补上缺失的return:

public function avatar(): Attribute
{
    return Attribute::make(
        get: function (?string $value, array $attributes) {
            return asset(str_replace('public', 'storage', self::$avatarPath)
                . '_' .
                $this->full_name . '_' . $attributes['id'] . '.webp'
            );
        },
    );
}

方案2:手动拼接full_name(适合必须用静态的场景)

直接从$attributes里取first_name和last_name拼接,不依赖附加属性:

public function avatar(): Attribute
{
    return Attribute::make(
        get: static function (?string $value, array $attributes) {
            $fullName = $attributes['first_name'] . ' ' . $attributes['last_name'];
            return asset(str_replace('public', 'storage', self::$avatarPath)
                . '_' .
                $fullName . '_' . $attributes['id'] . '.webp'
            );
        },
    );
}

注:此方案要求查询时已选中first_name和last_name,你的代码已经满足这个条件。

额外修正

adminTableData方法的返回值声明错误——实际返回JSON字符串,却声明为Builder,建议修改:

public static function adminTableData(): string
{
    return self::query()->with(['user' => function($query) {
        $query->select('id', 'first_name', 'last_name');
    }])->paginate(10)->toJson();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 13:51:21