Laravel通过hasOne获取属性
Laravel going through hasOne to get attributes
我有以下型号。
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
我 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;
}
但我不知道如何访问 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;
}
访问者 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
中包含 color
和 species
,因为它们不是数据库列
- 你不需要在关系方法中声明列名(例如
$this->hasOne(MonsterColor::class,'id','color_id')
),除非它们是非标准的——你的不是
- 如果一个关系 returns 一个集合,它应该用复数命名(即不是
$player->monster
如你的问题)
- 调查 eager loading 关系。
我有以下型号。
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
我 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;
}
但我不知道如何访问 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;
}
访问者 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
中包含color
和species
,因为它们不是数据库列 - 你不需要在关系方法中声明列名(例如
$this->hasOne(MonsterColor::class,'id','color_id')
),除非它们是非标准的——你的不是 - 如果一个关系 returns 一个集合,它应该用复数命名(即不是
$player->monster
如你的问题) - 调查 eager loading 关系。