Laravel salva / aggiorna la relazione molti a molti


89

Qualcuno può aiutarmi su come salvare la relazione molti a molti? Ho attività, l'utente può avere molte attività e l'attività può avere molti utenti (molti a molti). Quello che voglio ottenere è che nel modulo di aggiornamento l' amministratore può assegnare più utenti a un'attività specifica. Questo viene fatto tramite input di selezione multipla html

name="taskParticipants[]"

Il problema qui è che attraverso lo stesso modulo (input) puoi aggiungere / rimuovere utenti, ecco perché devo usare sync (). Forse dovrei cominciare dall'inizio ma non so da dove cominciare ...

Questo è il mio modello utente:

public function tasks()
{
    return $this->belongsToMany('Task','user_tasks');
}

Modello di attività

public function taskParticipants()
{
    return $this->belongsToMany('User','user_tasks');
}

TaskController

public function update($task_id)
{
    if (Input::has('taskParticipants'))
    {
        foreach(Input::get('taskParticipants') as $worker)
        {
            $task2 = $task->taskParticipants->toArray();
            $task2 = array_add($task2,$task_id,$worker);
            $task->taskParticipants()->sync(array($task2));
        }
    }
}

Questa è la struttura delle attività delle tabelle id | titolo | scadenza

user_tasks
id|task_id|user_id

Ho aggiornato il mio codice. link
SuperManSL

4
$workers = Input::get('taskParticipants'); $task->taskParticipants()->sync($workers);e questo è tutto ciò di cui hai bisogno, a patto che da quel modulo passi tutti gli utenti, assegnati all'attività.
Jarek Tkaczyk

@JarekTkaczyk Grazie, è stato magico.
Ryu_hayabusa

Risposte:


200

tldr; Utilizzare synccon 2 ° paramfalse


La relazione molti-a-molti è presente belongsToManysu entrambi i modelli:

// Task model
public function users()
{
  return $this->belongsToMany('User', 'user_tasks'); // assuming user_id and task_id as fk
}

// User model
public function tasks()
{
  return $this->belongsToMany('Task', 'user_tasks');
}

Per aggiungere una nuova relazione utilizzare attachosync .

La differenza tra i due è:

1 attach aggiungerà una nuova riga alla tabella pivot senza verificare se è già presente. Va bene quando hai dati aggiuntivi collegati a quella relazione, ad esempio:

User e Exam collegato con la tabella pivotattempts: id, user_id, exam_id, score

Suppongo che questo non sia ciò di cui hai bisogno nella tua situazione:

$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6]

$user->tasks()->attach([5,6,7]);
// then
$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6,5,6,7]

2 sync d'altra parte, rimuoverà tutte le relazioni e le imposterà di nuovo:

$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6]

$user->tasks()->sync([1,2,3]);
// then
$user->tasks()->getRelatedIds(); // [1,2,3]

oppure imposterà nuove relazioni senza staccare il precedente AND senza aggiungere duplicati:

$user->tasks()->sync([5,6,7,8], false); // 2nd param = detach
// then
$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6,7,8]

8
Sarebbe bello se fosse documentato nei documenti principali piuttosto che nei documenti API! Rock on. +1.
ceejayoz

Mi piace molto la seconda soluzione con sincronizzazione e secondo parametro. Come ho detto nel commento qui sotto, non posso permettermi di non usare il distacco. La storia è che l'amministratore può assegnare attività agli utenti. Seleziona gli utenti dal menu a discesa (più), il campo è partecipanti []. Quindi ...: Passaggio 1: l'amministratore assegna l'attività A a tre utenti (il tuo metodo funziona, abbiamo 3 record nel DB) Passaggio 2: l'amministratore aggiorna l'attività A e aggiunge due utenti (il tuo metodo funziona, abbiamo 5 record nel DB) Passaggio 3: l'amministratore aggiorna l'attività A e rimuove 1 utente (il tuo metodo fallisce, abbiamo ancora 5 utenti invece di 4) il mio metodo di aggiornamento il mio codice
SuperManSL

1
Puoi semplificare la tua query sulla relazione solo $this->belongsToMany('User')se usi il nome della tabella in ordine alfabetico e singolare (quindi task_userinvece di user_tasks)
Kousha

@Rok se passi sempre un array di tutti gli utenti correlati, quindi usa synccon il distacco, senza preoccupazioni. Suggerisco di utilizzare 2nd param impostato su false ogni volta che desideri "aggiungere una nuova attività per un utente" o "assegnare un utente a un'attività", quando passi uno solo iddel modello correlato.
Jarek Tkaczyk

1
@FabioAntunes syncrestituisce un array con detached, attachede updatedle liste. attachnon restituisce nulla, ma in entrambi i casi si otterrebbe un'eccezione se accadesse qualcosa di inaspettato nelle chiamate db.
Jarek Tkaczyk

109

Ecco le mie note su come salvare e aggiornare tutte le relazioni eloquenti.

in uno a uno :

Devi usare HasOne sul primo modello e BelongsTo sul secondo modello

per aggiungere record sul primo modello ( HasOne ) utilizzare il salvataggio  funzione di

esempio:    $post->comments()->save($comment);

per aggiungere record sul secondo modello ( BelongsTo ) utilizzare l'  associato funzione di

esempio:    $user->account()->associate($account);    $user->save();


in uno a molti :

Devi usare HasMany sul primo modello e BelongsTo sul secondo modello

per aggiungere record sulla prima tabella ( HasMany ) utilizzare le funzioni save  o saveMany

esempio:    $post->comments()->saveMany($comments);

per aggiungere record sul secondo modello ( BelongsTo ) utilizzare la  funzione di associazione

esempio:    $user->account()->associate($account);    $user->save();


in molti a molti :

Devi usare  BelongsToMany sul primo modello e BelongsToMany sul secondo modello

per aggiungere record sulla tabella pivot utilizzare le funzioni di collegamento o sincronizzazione

  • entrambe le funzioni accettano un singolo ID o un array di ID 

  • la differenza è che l'allegato controlla se il record esiste già nella tabella pivot mentre la sincronizzazione no

esempio: $user->roles()->attach($roleId);


in Polymorphic One to Many :

Devi usare  MorphMany sul modello principale e  MorphTo su tutti i modelli (*** in grado)

per aggiungere record su tutti gli altri modelli usa il  salvataggio

esempio:    $course->tags()->save($tag);

la tabella pivot dovrebbe avere le seguenti colonne:

. ID modello principale

. (*** in grado) ID

. (*** in grado) Digitare


in Polymorphic Many to Many :

Devi usare  MorphByMany sul modello principale e  MorphToMany su tutti i modelli (*** in grado)

per aggiungere record su tutti gli altri modelli usa save o saveMany

esempio:    $course->tags()->save($tag);

esempio:    $course->tags()->saveMany([$tag_1, $tag_2, $tag_3]);

la tabella pivot dovrebbe avere le seguenti colonne:

. ID modello principale

. (*** in grado) ID

. (*** in grado) Digitare


in Has Many Through (scorciatoia):

Devi usare HasManyThrough sul primo tavolo e avere le normali relazioni sugli altri 2 tavoli

questo non funziona per le relazioni ManyToMany (dove c'è una tabella pivot)

tuttavia c'è una soluzione piacevole e facile proprio per questo.


Ecco un articolo che ho scritto, ispirato da questa risposta. Importante da controllare: https://hackernoon.com/eloquent-relationships-cheat-sheet-5155498c209


In realtà ho inserito questa risposta quando avevano già più di 40 Mi piace sulla risposta corretta, ma sì, so quanto sia utile per me, sono contento che ti piaccia :)
Mahmoud Zalt

1
Vorrei che tu sapessi che sei un salvatore
Chay22

1
questa è un'ottima risposta.
caro

1
come aggiornare uno alla relazione di maggio. hai spiegato come aggiungere. potresti spiegare anche l'aggiornamento? esiste un metodo per aggiornare i record come updateManyqualcosa del genere? grazie
Hamidreza

4

syncWithoutDetaching([$id_one, $id_two, $id_three]);è quello che stai cercando. In realtà fa esattamente la cosa [ synccon il 2 ° parametro false]!


0

La syncfunzione cancella le relazioni in uscita e rende l'array l'intero elenco di relazioni. Vuoi attachinvece aggiungere relazioni senza rimuovere gli altri.


Non posso usare l'allegato perché sto usando questo codice all'interno del metodo di aggiornamento. La storia è che l'amministratore può aggiornare l'attività e inserire i partecipanti di input [] con gli utenti che parteciperanno all'attività. Quindi devo controllare se esiste ed eliminarlo (o non aggiungere un nuovo record) o se non esiste aggiungerlo.
SuperManSL
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.