2016-05-11 10 views
0

So habe ich eine einfache Tabelle:Merging zwei Arrays mit Modellen

messages: 
- id 
- user_id - user that "sent" the message (the author) 
- to_user_id - user that "received" the message 
- body 
- created_at 
- updated_at 

Ich bin mit Laravel 5.2, habe ich ein Modell, das wie folgt aussieht:

class Message extends Model 
{ 
    public function user() 
    { 
     return $this->belongsTo('App\Models\User'); //This should return only the sender 
    } 

    public function scopeSentByUser($query, $user_id) 
    { 
     return $query->where('user_id', '=', $user_id); 
    } 

    public function scopeReceivedByUser($query, $user_id) 
    { 
     return $query->orWhere('to_user_id', '=', $user_id); 
    } 

    public function scopeNewestFirst($query) 
    { 
     return $query->orderBy('created_at', 'DESC'); 
    } 
} 

In meinem Controller Ich habe zwei Variablen, die wenige Modellmethoden aufrufen:

Ich frage mich, wie kann ich sie in Threads zusammenführen. Im Grunde habe ich nichts wie Threads in meiner App. Benutzer können Nachrichten zwischen schreiben und es ist ein einzelner Thread. Wie das soziale Netzwerk von Zuckerberg oder der Chat-Client von Google.

Ich möchte, dass sie zu halten, um in der Lage sein (oder kann ich sie nach dem Gruppieren bestellen) und haben so etwas wie:

$threads = [ 
    [ 
     'participants' => [1, 2], //those are users' ids 
     'messages' => [ 
      (Model)Message, 
      (Model)Message, 
      (Model)Message, 
      (Model)Message, 
      (Model)Message 
     ] 
    ] 
]; 

bearbeiten:

auf der akzeptierte Antwort Basierend I ended up mit dem folgenden Code:

$query = self::where('user_id', $logged_user_id)->orWhere('to_user_id', $logged_user_id)->get(); 

$inUserId = $query->lists('user_id')->toArray(); 
$inToUserId = $query->lists('to_user_id')->toArray(); 

$mergedIds = array_merge($inUserId, $inToUserId); 
$uniqueIds = array_unique($mergedIds); 

unset($uniqueIds[array_search($logged_user_id, $uniqueIds)]); //Remove logged in user ID 

$combinations = []; 
foreach ($uniqueIds as $id) { 
    $combinations[] = [$id, $logged_user_id]; 
} 
$threads = []; 
foreach ($combinations as $key => $combo) { 
    $threads[] = [ 
     'receiver' => $combo[0] == $logged_user_id ? User::find($combo[1]) : User::find($combo[0]), 
     'messages' => self::where(function ($query) use ($combo) { 
      $query->where('user_id', $combo[0])->where('to_user_id', $combo[1]); 
     })->orWhere(function ($query) use ($combo) { 
      $query->where('user_id', $combo[1])->where('to_user_id', $combo[0]); 
     })->orderBy('created_at', 'ASC')->get() 
    ]; 
} 

return $threads; 

die Unterschiede sind: pluck() ist repla ced mit lists()->toArray()

Nach dem Zusammenführen der Arrays (array_merge) und nur die eindeutigen Werte (array_unique) Ich deaktiviere die angemeldete Benutzer-ID. Weil ich es nicht brauche.

Auch diese Methode entfernt, um die verschiedenen Paare zu erhalten, da es nicht anwendbar ist. Ich glaube, es sollte jetzt richtig funktionieren.

Wird nach einigen komplexeren Tests aktualisiert.

Ich habe dies als Update geschrieben, da ich Antworten nicht bearbeiten kann. Und meine Korrekturen sind zu wenig, um meine eigene Antwort zu veröffentlichen.

+0

Woher kommt die andere Benutzer-ID? – Samsquanch

+0

Nun, wenn ich Ihnen eine Nachricht gebe, wird meine ID in 'user_id' und Ihre in' to_user_id' gespeichert. Aber wenn Sie mir eine Nachricht schicken, wird meine als 'to_user_id' und Ihre als' user_id' gespeichert. –

+0

Also wollen Sie, sagen wir, eine Methode, wo Sie 'getMessagesSentBetweenUserIds (1, 2)' tun können und es wird Ihr '$ threads' Array zurückgeben? Oder versuchen Sie, alle Nachrichten für alle Benutzer auf einmal zu erhalten? Denn wenn Sie nur Ihre "sentByUser" - und "receivedByUser" -Methoden verwenden, die Sie jetzt haben, könnten Sie möglicherweise Nachrichten von anderen Nutzern außerhalb von 1 und 2 einziehen, was Sie nicht wollen. – Samsquanch

Antwort

1

So etwas sollte funktionieren. Ich habe es wie eine Modellmethode geschrieben, aber Sie können es auch zu einem Controller hinzufügen, indem Sie $this in den richtigen Modellnamen ändern.

public function getThreads($id) { 
    $query = $this->where('user_id', $id)->orWhere('to_user_id', $id)->get(); 
    // get the unique user id's 
    $user_ids = array_unique (array_merge ($query->pluck('user_id'), $query->pluck('to_user_id'))); 

    // get the distinct pairs 
    // taken from here: http://stackoverflow.com/a/3770452/485418 
    $num_ids = count($user_ids); 
    for ($i = 0; $i < $num_ids; $i++) 
    { 
     for ($j = $i+1; $j < $num_ids; $j++) 
     { 
      $combinations[] = array($user_ids[$i], $user_ids[$j]); 
     } 
    } 

    $threads = array(); 
    $tmp = array(); 
    // build the threads array 
    foreach ($combinations as $key => $combo) { 
     $tmp = array(); 
     $tmp['participants'] = $combo; 
     $tmp['messages'] = $this->where(function($query) { 
             $query->where('user_id', $combo[0])->where('to_user_id', $combo[1]); 
            })->orWhere(function($query) { 
             $query->where('user_id', $combo[1])->where('to_user_id', $combo[0]); 
            })->orderBy('created_at', 'DESC')->get(); 
     $threads[] = $tmp; 
    } 

    return $threads 
} 
+0

Ich habe 'pluck()' nach 'lists() -> toArray()' bearbeitet und eine statische Funktion gemacht. Ich werde Ihre Antwort bearbeiten, fühlen Sie sich frei, um es rückgängig zu machen, wenn Sie irgendwelche Notizen haben. –

+0

Eigentlich habe ich meine Frage mit allem, was ich geändert habe, aktualisiert, damit das funktioniert (ich denke * es funktioniert einwandfrei). –

0

Vielleicht so etwas wie folgt aus:

$messages = array(); 
foreach ($this->sent as $message) { 
    $messages[] = $message; 
} 
foreach ($this->received as $message) { 
    $messages[] = $message; 
} 
$messages = collect($messages); 
$participants = $messages->keyBy('user_id')->keys(); 

Wenn Sie $messages Sammlung haben, können Sie alle diese Methoden verwenden: https://laravel.com/docs/master/collections