Laravel通过hasOne获取属性

Laravel going through hasOne to get attributes

我有以下型号。

然后,在播种后,在 php artisan tinker 我 select 一名玩家:

$player = Player::all()->first();

有效。然后我检查怪物。

Illuminate\Database\Eloquent\Collection {#3561
     all: [
       App\Models\Monster {#3569
         id: 1,
         created_at: "2021-12-09 16:39:29",
         updated_at: "2021-12-09 16:39:29",
         name: "Alberto Mills",
         level: 17,
         currHealth: 68,
         maxHealth: 76,
         strength: 42,
         defense: 29,
         movement: 13,
         species: 28,
         color: 34,
         player_id: 1,
       },
       App\Models\Monster {#4505
         id: 2,
         created_at: "2021-12-09 16:39:29",
         updated_at: "2021-12-09 16:39:29",
         name: "Darlene Price",
         level: 9,
         currHealth: 16,
         maxHealth: 32,
         strength: 44,
         defense: 19,
         movement: 61,
         species: 28,
         color: 34,
         player_id: 1,
       },
     ],
   }

然后$player->monster->get(0)->color;

 App\Models\MonsterColor {#4508
     id: 34,
     name: "Red_Blue",
   }

现在我相信我可以将 getSpeciesAttribute()getSpeciesAttribute() 添加到直接 return 名称中,或者做类似的事情:

public function getSpeciesAttribute($value)
{
    $colors = explode("_",$value->name); // I don't know if this is how I get the name
    $out = "Your monster's color is ";
    if (count($colors) > 1) {
        $out .= "a mesh of " . implode(", ",array_slice($colors, 0, -1)) . " and ";
    }
    $out .= array_pop($colors);
    return $out;
}

但我不知道如何访问 MonsterColorname 属性。

编辑:

这是 Monster、MonsterColor 和 MonsterSpecies 模型。

class Monster extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'level',
        'currHealth',
        'maxHealth',
        'strength',
        'defense',
        'movement',
        'species',
        'color'
    ];

    public function player()
    {
       return $this->belongsTo(Player::class);
    }

    public function species()
    {
       return $this->hasOne(MonsterSpecies::class,'id','species_id');
    }

    public function color()
    {
        return $this->hasOne(MonsterColor::class,'id','color_id');
    }

    public function getSpeciesAttribute()
    {
        return $this->species->name;
    }

    public function getColorAttribute()
    {
        return $this->color->name;
    }
}

class MonsterColor extends Model
{
    use HasFactory;

    public $timestamps = false;
}

class MonsterSpecies extends Model
{
    use HasFactory;

    public $timestamps = false;
}

访问者 getColorAttribute() 在模型 class 上创建了一个“虚拟”color 属性。但是你也有一个叫做 color() 的关系方法。关系方法还会创建您尝试使用 $this->color.

访问的虚拟属性

所以问题只是名称冲突之一。最简单的解决方案是将访问器重命名为其他名称。

你的其他accessor也是一样的问题,也是不接受参数;它们作为属性访问,因此无法传递一个。

public function getColorNameAttribute()
{
    return $this->color->name;
}

public function getSpeciesDescriptionAttribute()
{
    $colors = explode("_", $this->color->name);
    return sprintf(
        "Your monster's color is %s",
        implode(" and ", $colors)
    );
}

现在您可以通过 $player->monsters[0]->color_name$player->monsters[0]->species_description 访问这些内容。


一些其他注意事项:

  • 您不应该在 $fillable 中包含 colorspecies,因为它们不是数据库列
  • 你不需要在关系方法中声明列名(例如 $this->hasOne(MonsterColor::class,'id','color_id')),除非它们是非标准的——你的不是
  • 如果一个关系 returns 一个集合,它应该用复数命名(即不是 $player->monster 如你的问题)
  • 调查 eager loading 关系。