【问题标题】:Laravel going through hasOne to get attributesLaravel 通过 hasOne 获取属性
【发布时间】: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;
}

但我不知道如何访问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;
}

【问题讨论】:

  • 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(); });

标签: php laravel eloquent


【解决方案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 中不应包含 colorspecies,因为它们不是数据库列
  • 你不需要在关系方法中声明列名(例如$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 访问它们。
  • 问题,将关系方法MonsterSpeciesMonsterColor 以及访问器getSpeciesAttributegetColorAttribute 设置为更简洁/更可取,从那时起$monster->MonsterSpecies 实际上返回一个MonsterSpecies model 和 $monster->species 只返回名称??
  • 那个错误意味着你的种族和肤色关系应该是belongsTo,而不是hasOne。见laravel.com/docs/8.x/eloquent-relationships#one-to-many。将它们命名为对您最有意义的名称,没有硬性规定。但是有一些约定,例如访问属性时,通常使用snake case ($monster->monster_species)
  • 为了清楚起见,我还将在MonsterSpeciesMonsterColor 模型上添加public function monsters() { return $this->hasMany(Monster::class);}`。即使从未使用过,它也可以是一个很好的健全性检查。在关系的一侧看到hasMany,就知道另一侧应该是belongsTo
猜你喜欢
  • 1970-01-01
  • 2017-07-24
  • 2015-08-14
  • 2017-06-21
  • 2016-07-30
  • 2012-09-28
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
相关资源
最近更新 更多