Связывание нескольких отдельных экземпляров одной и той же модели в Laravel - PullRequest
0 голосов
/ 05 ноября 2019

Я работаю над проектом, в котором есть события, каждое из которых относится к двум отдельным формам на двух отдельных отношениях - бронирование и опрос. Эти формы одинаково сконструированы, поэтому нет необходимости использовать две совершенно разные модели форм - вместо этого я хотел использовать полиморфное отношение, но оказалось, что это невозможно.

Каков подходящий способструктурировать эти отношения?

  • События имеют одну форму бронирования или не имеют ее
  • События имеют одну или нет форму опроса
  • Формы представляют собой отдельную таблицу

Что я пробовал:

  • Полиморфное отношение: несовместимо с двумя отношениями к одной и той же модели.
  • Имеет одноотношение: при этом использовались booking_id и survey_id, но отказывалось устанавливать одно из этих полей.
  • Имеет много связей с полем типа: затруднялось простое сохранение форм, так как это было невозможночтобы сохранить в одиночных отношениях. Также не было ограничений на количество форм.
class Event extends Model
{
    public function booking()
    {
        return $this->hasOne(Form::class, 'id', 'booking_form_id');
    }

    public function survey()
    {
        return $this->hasOne(Form::class, 'id', 'survey_form_id');
    }
}

...

class Form extends Model
{
    public function event()
    {
        return $this->belongsTo(Event::class);
    }
}

...

$event = new Event;
$event->name = 'Event';
$event->save();

$booking = new Form;
$booking->name = 'booking';
$event->booking()->save($booking);

$survey = new Form;
$survey->name = 'survey';
$event->survey()->save($survey);

...

Schema::create('events', function (Blueprint $table) {
    $table->bigIncrements('id');

    $table->string('name');

    $table->unsignedInteger('booking_form_id')->nullable()->index();
    $table->unsignedInteger('survey_form_id')->nullable()->index();

    $table->timestamps();
});

Schema::create('forms', function (Blueprint $table) {
    $table->increments('id');

    $table->string('name');

    $table->timestamps();
});

Что было бы предпочтительнее:

  • Использование полиморфных отношений, которые позволили быформы, которые будут использоваться в других частях приложения.
  • Использование нескольких отношений hasOne, чтобы ограничить количество форм до одной для каждого типа.

1 Ответ

0 голосов
/ 05 ноября 2019

Я думаю, что вы неправильно указали свой параметр. Это hasOne($related, $foreignKey, $localKey)

class Event extends Model
{
    /* if you haven't changed the default primary keys, $localKey should be equal to 'id' */ 
    public function booking()
    {
        return $this->belongsTo(Form::class, 'booking_form_id');
    }

    public function survey()
    {
        return $this->belongsTo(Form::class, 'survey_form_id');
    }
}
class Form extends Model
{
    public function booking_event()
    {
        return $this->hasOne(Event::class, 'booking_form_id');
    }

    public function survey_event()
    {
        return $this->hasOne(Event::class, 'survey_form_id');
    }
}

Теперь есть 2 способа сделать это.

  1. Если форма может принадлежать обоим видам событий, вам необходимо вернуть коллекцию при доступе к $form->event.
  2. Если форма может принадлежать только одному виду событий, вам нужно угадать, какого рода и вернуть модель при доступе к $form->event.
# Form model
# 1. can be achieved using an accessor. Cannot be eager loaded but can be appended with the $appends Model property
public function getEventsAttribute()
{
    return collect([$this->booking_event, $this->survey_event]);
}
# Form model
# 2. can be achieved using a relationship that guesses which relation it should return. Since it returns a relationship, it can be eager loaded.
public function event()
{
    return ($this->booking_event()->count() != 0) ? $this->booking_event() : $this->survey_event();
}
...