2015-10-26 5 views
17

Ho due modelli che vorrei unire in un'unica timeline. Sono stato in grado di farlo creando una vista in mysql che normalizza e unisce le tabelle. Ho creato un modello per questa vista, NewsFeed. Funziona bene se non desidero il modello correlato Comment. Mi sono avvicinato a questo superando il metodo getMorphClass sul modello. Questo mi consente di ottenere i commenti correlati per le immagini, ma non i post, perché quando si chiama getMorphClass il modello non ha dati.Due modelli in una query impaginata con relazioni caricate avide usando Laravel

Sono aperto a qualsiasi approccio su come risolvere questo problema, non solo nel modo in cui sto proponendo, ma non voglio estrarre più dati di quelli che devo dal database.

Feed Novità

<?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 View

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`; 

immagini tavolo

id 
    user_id 
    title 
    img 
    img_width 
    img_height 
    img_other 
    description 
    created_at 
    updated_at 

messaggi

id 
    user_id 
    title 
    body 
    created_at 
    updated_at 
+0

non è possibile utilizzare solo caricamento ansioso? $ var = Picture :: with ('posts', 'comments') ... – futureweb

+0

Il più vicino sarebbe ottenere User :: with (['posts', 'pictures']) -> get(); che non ti dà contenuto impaginato. Ho pensato di fare qualcosa come '$ user-> posts() -> paginate (15);' e '$ user-> pictures() -> paginate (15);' quindi unire le collezioni, ma diventa problematico una volta desidera set di record aggiuntivi. – whoacowboy

+0

perché non impaginare 'Utente :: con (['post', 'immagini']) -> paginate (15);' o anche 'Utente :: con (['post', 'posts.comments', 'immagini' ]) -> paginate (15); 'e anche un metodo di commenti sul modello dei post? – futureweb

risposta

7

Tu sei molto vicino con la vostra idea di costruire una visione. Infatti, se si crea una tabella reale invece di una vista, la soluzione diventa abbastanza semplice.

Con un oggetto polymorph 'FeedItem' che punta alla classe Post o Picture, è possibile allegare i commenti direttamente a FeedItem con una relazione hasMany.

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'); 
    } 
} 

Questa soluzione può richiedere un po 'di refactoring sui moduli dal momento che sarà necessario creare una voce per ogni voce FeedItem Post e l'ingresso immagine. I listener di eventi per Picture :: created e Post :: created dovrebbero fare il trucco (http://laravel.com/docs/5.1/eloquent#events).

Una volta che è impostato, è possibile utilizzare:

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

Anche se io non conosco né laravel eloquente per quella materia, Ecco il mio input su questo.

Supponendo che stai ricevendo l'uscita da questo punto di vista SQL in $Entries

quanto ho capito Eloquente consente di impostare i valori per te stesso, quindi qualcosa di simile potrebbe funzionare per voi (non sono sicuro sulla sintassi o l'uso per quella materia).

$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; 
Problemi correlati