Edwin Krause
Edwin Krause

Reputation: 1806

Eloquent one-to-one relationship to same model

I have existing data to work with: I got a table that contains all sportevents called sportevents.

id ....
name ....
....

These sportevents have a pivot table that define relations to the "same" sportevent happened in the previous year and the one of next year. Bit confusing design, but here is the table called eventrelations: I try to explain with years 2018 and 2019

id ....
event1: sportevent_id of 2019 event
event2: sportevent_id or 2018 event
....

My approach would be to create a Model called Eventrelation with the following relations:

public function previous(){
    return $this->belongsTo('App\Sportevent','event1','id' );
}

public function next(){
    return $this->belongsTo('App\Sportevent','event2','id' );
}

and in my Sportevent Model I would do the following:

public function previousEvent(){
    return $this->hasOne('App\Eventrelation','event2','id' );
}

public function nextEvent(){
    return $this->hasOne('App\Eventrelation','event1','id');
}

Although this is gonna work, I don't think this is the proper way to do it. I have setup other relations with a pivot table, but this one seems to be a bit more tricky considering the existing data structure and the relationship to the same Model. Any advice would be much appreciated.

UPDATE

I made it work the way I proposed above, the reason why I would rather have a cleaner version is to reduce the code (that's part of being cleaner :-)). So here is how I call these relations and how I would rather call them:

    $previousEvent = $thisEvent->previousEvent ? $thisEvent->previousEvent->previous : null;
    $nextEvent = $thisEvent->nextEvent ? $thisEvent->nextEvent->next : null;

    // Better would be:
    $previousEvent = $thisEvent->previousEvent;
    $nextEvent = $thisEvent->nextEvent;

Upvotes: 0

Views: 116

Answers (2)

Edwin Krause
Edwin Krause

Reputation: 1806

Here is the full solution (Not needing the Pivot table at all)

I added 2 fields to my sportsevents table

previous_sportevent_id  int(11) Null    
next_sportevent_id  int(11) Null

I then migrated the data of the eventrelations table to the new columns

UPDATE `sportevents`
INNER JOIN eventrelations ON eventrelations.event1 = sportevents.id
SET sportevents.previous_sportevent_id = eventrelations.event2

UPDATE `sportevents`
INNER JOIN eventrelations ON eventrelations.event2 = sportevents.id
SET sportevents.next_sportevent_id = eventrelations.event1

In the Sportevent model I changed the relations:

public function previousEvent(){
    return $this->hasOne('App\Sportevent','id','previous_sportevent_id' );
}

public function nextEvent(){
    return $this->hasOne('App\Sportevent','id','next_sportevent_id');
}

I can now use the new relations properly and clean in my Resource

return [
      'id' => $this->id,
      ......
      'nextEvent' => $this->nextEvent,
      'previousEvent' => $this->previousEvent,
    ];

The Model Eventrelation and table eventrelations now can be deleted. I hope this will help someone...

Upvotes: 1

Fatemeh Majd
Fatemeh Majd

Reputation: 739

you do not need a pivot model at all. you can make a relationship with a class itself.

in your sportsevent model:

public function previousEvent()
{
  return $this->belongsToMany(SportsEvent::class, 'pivot_table_name', 'event_1', 'id');
}

public function nextEvent()
{
  return $this->belongsToMany(SportsEvent::class, 'pivot_table_name', 'event_2', 'id');
}

if there is only one event, you can add a term ->first() to the end of relationships.

BUT, you can also simply add two columns, 2018_event and 2019_event and add the ids of events there, and then use hasOne relationship. your call

Upvotes: 0

Related Questions