Laravel 通过 hasOne 获取属性
Posted
技术标签:
【中文标题】Laravel 通过 hasOne 获取属性【英文标题】:Laravel going through hasOne to get attributes 【发布时间】:2022-01-14 14:31:48 【问题描述】:我有以下型号。
Player
(hasMany(Monster::class)
)
Monster
hasOne(MonsterSpecies::class,'id','species_id')
hasOne(MonsterColor::class,'id','color_id')
)
MonsterSpecies
MonsterColor
(两者几乎都是空的,只是public $timestamps = false;
)
然后,播种后,在php artisan tinker
中选择一名玩家:
$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()
来直接返回名称,或者执行以下操作:
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;
但我不知道如何访问MonsterColor
的name
属性。
编辑:
这是 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;
【问题讨论】:
getSpeciesAttribute
是什么型号的?
@Andy on Monster,用 Monster 类更新了 OP。
看起来您在编辑中的内容应该可以工作..您是否遇到某种错误或意外行为?如果我不得不猜测,我认为您会遇到具有相同名称的关系和属性的问题。
可能对他有用,他想要我认为加入 laravel 的所有属性我猜Monster::with("player")->with("species")->with("color")->get();
Player::with("monster",function($e) $e->with("species")->with("color")->get(); );
【参考方案1】:
访问器getColorAttribute()
在模型类上创建一个“虚拟”color
属性。但是您也有一个名为color()
的关系方法。关系方法还会创建虚拟属性,您尝试使用 $this->color
访问这些属性。
所以问题只是名称冲突之一。最简单的解决方案是将访问器重命名为其他名称。
问题与您的其他访问器相同,并且它们不接受参数;它们作为属性访问,因此无法传递一个。
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
中不应包含 color
和 species
,因为它们不是数据库列
你不需要在关系方法中声明列名(例如$this->hasOne(MonsterColor::class,'id','color_id')
),除非它们是非标准的——你的不是
如果一个关系返回一个集合,它应该用复数命名(即不是$player->monster
,如您的问题)
请查看eager loading 的关系。
【讨论】:
创建怪物时玩家可以选择颜色和物种,它们是数据库列。如果我从关系方法中删除列名,我会得到Column not found: 1054 Unknown column 'monster_colors.monster_id' in 'where clause' (SQL: select * from
monster_colors` 其中 monster_colors
.monster_id
= 1 和 monster_colors
.monster_id
不是空限制 1. I renamed to
getSpeciesNameAttribute` 和 getColorNameAttribute
和我可以通过$player->monsters->get(0)->colorName
和$player->monsters->get(0)->color_name
访问它们。
问题,将关系方法MonsterSpecies
和MonsterColor
以及访问器getSpeciesAttribute
和getColorAttribute
设置为更简洁/更可取,从那时起$monster->MonsterSpecies
实际上返回一个MonsterSpecies
model 和 $monster->species
只返回名称??
那个错误意味着你的种族和肤色关系应该是belongsTo
,而不是hasOne
。见laravel.com/docs/8.x/eloquent-relationships#one-to-many。将它们命名为对您最有意义的名称,没有硬性规定。但是有一些约定,例如访问属性时,通常使用snake case ($monster->monster_species
)
为了清楚起见,我还将在MonsterSpecies
和MonsterColor
模型上添加public function monsters() return $this->hasMany(Monster::class);
`。即使从未使用过,它也可以是一个很好的健全性检查。在关系的一侧看到hasMany
,就知道另一侧应该是belongsTo
。以上是关于Laravel 通过 hasOne 获取属性的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 中 BelongsTo 和 HasOne 有啥区别
理解 Laravel 中的 hasOne() 和 belongsTo() 函数