2015-10-26 4 views
17

Ich habe zwei Modelle, die ich in einer Timeline zusammenführen möchte. Ich konnte dies tun, indem ich eine Sicht in mysql erstelle, die die Tabellen normalisiert und verbindet. Ich habe ein Modell für diese Ansicht erstellt, NewsFeed. Dies funktioniert gut, wenn ich nicht verwandte Comment Modell wollen. Ich bin nahe daran gekommen, indem ich die getMorphClass Methode auf dem Modell überschrieben habe. Dies ermöglicht mir, die zugehörigen Kommentare für die Bilder zu erhalten, aber nicht für die Beiträge, denn wenn getMorphClass aufgerufen wird, hat das Modell keine Daten.Zwei Modelle in eine paginierte Abfrage mit eifrig geladenen Relationen mit Laravel

Ich bin offen für jeden Ansatz, wie man das löst, nicht nur die Art und Weise, wie ich vorschlage, aber ich möchte nicht mehr Daten als ich aus der Datenbank ziehen.

Newsfeed

<?php 

    namespace App\Users; 

    use App\Pictures\Picture; 
    use App\Social\Comments\CommentableTrait; 
    use App\Posts\Post; 
    use App\Users\User; 
    use Illuminate\Database\Eloquent\Model; 

    class UserFeed extends Model 
    { 
     use CommentableTrait; 

     public function user() 
     { 
      return $this->belongsTo(User::class); 
     } 

     public function getMorphClass(){ 
      if ($this->type == 'post'){ 
       return Post::class; 
      } 
      return Picture::class; 
     } 
    } 

MySQL Ansicht

CREATE VIEW 
    `user_feeds` 
AS SELECT 
    `posts`.`id` AS `id`, 
    `posts`.`user_id` AS `user_id`, 
    'post' AS `type`, 
    NULL AS `name`, 
    NULL AS `thumbnail`, 
    `posts`.`body` AS `body`, 
    `posts`.`updated_at` AS `updated_at`, 
    `posts`.`created_at` AS `created_at` 
FROM 
    `posts` 
UNION SELECT 
    `pictures`.`id` AS `id`, 
    `pictures`.`user_id` AS `user_id`, 
    'picture' AS `type`, 
    `pictures`.`name` AS `name`, 
    `pictures`.`thumbnail` AS `thumbnail`, 
    `pictures`.`description` AS `body`, 
    `pictures`.`updated_at` AS `updated_at`, 
    `pictures`.`created_at` AS `created_at` 
FROM 
    `pictures`; 

Bilder Tisch

id 
    user_id 
    title 
    img 
    img_width 
    img_height 
    img_other 
    description 
    created_at 
    updated_at 

Beiträge

id 
    user_id 
    title 
    body 
    created_at 
    updated_at 
+0

Können Sie nicht einfach eifrig laden? $ var = Picture :: with ('posts', 'comments') ... – futureweb

+0

Am nächsten wäre es, User :: with (['posts', 'pictures']) zu erhalten -> get(); was paginierten Inhalt nicht bekommt. Ich dachte an etwas wie $ user-> posts() -> paginate (15); und $ user-> pictures() -> paginate (15); dann die Sammlungen zusammenführen, aber es wird einmal problematisch will zusätzliche Datensätze. – whoacowboy

+0

warum nicht paginieren 'User :: mit (['posts', 'bilder']) -> paginate (15);' oder sogar 'User :: with (['posts', 'posts.comments', 'pictures' ]) -> paginate (15); 'und ziehe auch eine Kommentarmethode für das Posts-Modell? – futureweb

Antwort

7

Sie sind ganz in der Nähe mit Ihrer Idee, einen Blick zu bauen. Wenn Sie eine tatsächliche Tabelle anstelle einer Ansicht erstellen, wird die Lösung tatsächlich ziemlich einfach.

Mit einem polymorphen Objekt 'FeedItem', das auf Ihre Post-Klasse oder Picture-Klasse verweist, können Sie die Kommentare mit einer hasMany-Beziehung direkt an das FeedItem anhängen.

class FeedItem extends Model { 
    use CommentableTrait; 
    public function feedable() 
    { 
     return $this->morphTo(); 
    } 
} 

class Post extends Model { 
    public function feeditem() 
    { 
     return $this->morphOne('FeedItem', 'feedable'); 
    } 
} 

class Picture extends Model { 
    public function feeditem() 
    { 
     return $this->morphOne('FeedItem', 'feedable'); 
    } 
} 

Diese Lösung kann einigen Refactoring auf Ihren Formularen benötigen, da Sie einen FeedItem Eintrag für jeden Beitrag Eintrag und Bild Eintrag erstellen müssen. Event-Listener für Picture :: created und Post :: created sollten den Trick machen (http://laravel.com/docs/5.1/eloquent#events).

Sobald es eingerichtet ist, können Sie verwenden:

FeedItem::with('comments')->orderBy('created_at','desc')->paginate(15); 
1

Obwohl ich bin nicht vertraut mit Laravel noch Eloquent was das betrifft, meine Eingabe auf dieses hier.

Angenommen, Sie bekommen die Ausgabe von dieser SQL-Ansicht in $Entries

Wie ich verstehe Eloquent können Sie die Werte für sich selbst setzen, damit so etwas wie dies könnte für Sie arbeiten (Ich bin nicht sicher über die Syntax oder Verwendung für diese Angelegenheit).

$Collection = []; 
foreach($Entries as $Entry) { 
    if($Entry->type === 'post') { 
     $Collection[] = new Post($Entry->toArray())->with('comments'); 
    }else{ 
     $Collection[] = new Picture($Entry->toArray())->with('comments'); 
    } 
} 
return $Collection; 
Verwandte Themen