2016-12-29 10 views
2

Я пытаюсь окунуться в свои первые полиморфные отношения в Laravel 5.3.Полиморфные отношения Laravel 5.3

Отношения, которые я пытаюсь достичь, - это то, что «Редакция» будет иметь множество «Элементов», каждый элемент будет его собственной моделью и иметь заказ.

Так, например, у меня будут модели «ElementText», «ElementImage», «ElementButton», тогда «Редакция» будет иметь различные элементы, назначенные ей.

Вот почему я думаю, что мне нужны полиморфные отношения. Мне не нужны множественные отношения для каждого типа элемента в модели «Редакторы», я хочу иметь возможность просто получить все «Элементы» независимо от его типа и привести его в порядок.

Я думаю, что идея решение будет иметь «editorial_element» сводную таблицу со столбцами, как

editorial_id - integer 
order - integer 
element_id - integer 
element_type - string 

аналогично morphToMany например, в Laravel документации, но в этом примере необходимо указать модель для превращаться.

Так что я также задавался вопросом, должен ли я использовать метод morphTo() в моей редакции.

public function elements() { 
    return $this->morphTo(); 
} 

Но я думаю, что это означает, что я должен был бы добавить _type и _id столбцы моей передовиц таблицы, которая будет в обратном направлении (что позволяет одному элементу за редакционные)

Любая идея, если я могу установить отношения я требовать или я подхожу к нему неправильно?

ответ

1

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

editorials 
- id 
- title 
- etc... 

elements 
- editorial_id 
- elements_id 
- elements_type 

elements_image 
- id 
- url 

elements_text 
- id 
- text 

Тогда ваши модели могут быть.

class Editorial extends Model { 

    // ... 

    public function elements() { 
     return $this->hasMany(\Element::class); 
    } 

    // ... 

} 

class Element extends Model { 

    // ... 

    public function editorial() { 
     return $this->belongsTo(\Editorial::class); 
    } 

    public function image() { 
     return $this->belongsTo(\ElementImage::class, 'elements_id'); 
    } 

    public function text() { 
     return $this->belongsTo(\ElementText::class, 'elements_id'); 
    } 

    public function content() { 
     $type = $this->elements_type; 
     return $this->{$type}(); 
    } 

    // ... 

} 

class ElementImage extends Model { 

    // ... 

    public function element() { 
     return $this->hasOne(\Element::class, 'elements_id'); 
    } 

    // ... 

} 

class ElementText extends Model { 

    // ... 

    public function element() { 
     return $this->hasOne(\Element::class, 'elements_id'); 
    } 

    // ... 

} 

Может быть, тогда вы могли бы сделать все элементы реализовать интерфейс, который вынуждает render() метод на всех элементах, а затем вы можете сделать это в представлении:

@foreach($editorial->elements as $element) 
    {{ $element->content->render() }} 
@endforeach 

рендер метод может нести ответственность за форматирование и вывод содержимого.

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

+0

Понял, правда ли, думая, что модель «элементов» потребуется обновить вручную и больше не будет принимать методы attach(), detach(), используя этот подход? –

+0

'BelongsTo()' имеет 'associate()' и 'disassociate()', но я не могу представить себе ситуацию, когда вы будете манипулировать этими отношениями после их создания. Единственное, что я мог видеть в изменении, было бы «Редакционный - hasMany - Element», к сожалению, для этого не существует метода «sync()», но вы можете 'saveMany()'. –

+0

Я быстро перешел к этому подходу, прежде чем отправляться домой с работы раньше. Я не использовал представление, но сделал следующее: $ editorial = \ App \ Editorials :: with ('elements') -> first(); foreach ($ editorial-> elements as & $ elements) { \t \t $ elements-> content; \t}. Удивительно, как это влияет на производительность. –

0

Вы должны установить свои отношения, как показано ниже.

В вашей модели Editorial у вас должны быть методы для каждой модели Element*, на которой она переменилась. Например.

public function textElements() { 
    return $this->morphedByMany(ElementText::class, 'element'); 
} 


public function buttonElements() { 
    return $this->morphedByMany(ElementButton::class, 'element'); 
} 

В ваших Element* моделях вы должны иметь метод ниже, чтобы получить все Editorials, что это наложились.

public function editorials() 
    return $this->morphToMany(Editorial::class, 'element'); 
} 

Примечание: Есть некоторые проблемы с использованием полиморфных отношений, которые стоит отметить. Самое главное, что да, вы получаете некоторую простоту в структуре базы данных, но в то же время теряете ограничения внешнего ключа. Это означает, что если удаляется Element*, вам необходимо удалить любое значение Editorials, которое было изменено вручную, тогда как в нормальном отношении Many to Many вы можете установить ограничение внешнего ключа, и СУРБД сделает это за вас.

примечание 2: Прежде всего, я попытался бы увидеть, могут ли эти таблицы Element быть объединены в одну таблицу. Если они могут сделать вашу работу намного легче. Но если вам нужно использовать множество таблиц Element, я думаю, что оба способа в порядке. У каждого есть преимущество и недостаток. Это много таблиц отношений или полиморфных отношений, которые вам нужно для обеспечения согласованности базы данных самостоятельно. И в любом случае вы не можете сделать $editorial->elements() с отношениями.

+0

Итак, вы считаете, что единственным решением является наличие нескольких отношений для каждого типа элемента в редакции модели? В идеале я просто хочу, чтобы отношения «элементов» приводили их всех. –

+1

@ VinceLowe Отредактировал мой ответ. Прочтите примечание 2 –

+0

@FarzinFarzanehnia Эй, не могли бы вы проверить мой ответ? Просто любопытно видеть ваши мысли. –

Смежные вопросы