Question

Currently I have a one to many relationship setup. The way it works is one Champion has many Skins.

champions table has id, champion

skins table has id, set, champion, skin, champion_id - The champion field in this table is redundant, but that's only temporary.

The problem I'm getting is that when I call the skins table to receive champion name, it throws an error.

Models:

class Champion extends Eloquent {

    protected $table = 'champions';

    public function skin(){
        return $this->hasMany('Skin');
    }

}

class Skin extends Eloquent {

    protected $table = 'skins';

    public function champion() {
        return $this->belongsTo('Champion');
    }

}

Controller:

$champ = Champion::find(2);
foreach ($champ->skin as $c) {
    echo $c->set; //outputs the set for id=2
}

$skin = Skin::all();
foreach ($skin as $s) {
    echo $s->champion->champion; //errors out.

    echo $s->champion; //outputs all champion names (multiple times, if they have multiple skins).
}

What I want to out put is the Champion name, and then all of the skins the champion has. Perhaps someone can help tell me what's wrong and why this isn't working. I've looked at Laravel eloquent - One to many relationships where essentially is the same thing I'm doing, but still does not work.

Example output:

champion1
    skin1
    skin2
    skin3

champion2
    skin1
    skin2
Was it helpful?

Solution

Your relations are correct, the controller has flaws.

Problem is that you have a field called champion and the relation has the same name

The only thing I would change is relation name skin -> skins to make it verbose.

To make what you need do this:

// Champion model
public function skins()
{
   return $this->hasMany('Skin');
}

// controller
$champions = Champion::with('skins')->get(); // with() means eager loading to avoid n+1 issue

@foreach($champions as $champion)
   {{ $champion->id }}
   @foreach($champion->skins as $skin)
      <div> {{ $skin->set }} </div> // or whatever you like here
   @endforeach
@endforeach

Now the controller that doesn't work:

$skin = Skin::all();
foreach ($skin as $s) {

    echo $s->champion->champion; // $s->champion is a field on skins table    
    echo $s->champion; // outputs this field value
}

In this situation you can do this (but you'd rather not, rename field or relation instead):

echo $s->champion()->first()->id; // fetch related model and output its property

OTHER TIPS

Your models seem to be setup just fine. Unless you did some non standard things in the database like ommiting an id column, then you might have to specify the primary key and the foreign key on the relation. So the following should work just fine and output what you ara aiming for.

  • Get all your Champion model instances.
  • For each Champion print name and get skins by relation.
  • For each skin print the skin name.

Your query

$champions = Champion::all();

Blade template

@foreach($champions as $champion)
   <ul>
      <h3>{{$champion->name}}</h3>
      @foreach($champion->skin() as $skin)
         <li>{{$skin->name}}</li>
      @endforeach
   </ul>
@endforeach

Use

Skin::with(['champion'])->get();

instead of Skin::all(); to eager load the relationship data.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top