2016-02-16 27 views
6

Mam jedno do wielu polimorficznych związków dokładnie takich jak opisane in documentation, z tym że mam głosy zamiast zdjęć i kolumnę z liczbą całkowitą głosów w tabeli głosów. Tak:Zakres zapytania Laravel 5.2 w odniesieniu do polimorficznego związku

-votes 
--id 
--vote 
--voteable_id 
--voteable_type 

Model Zagłosuj ma voteable metody:

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

Ale dla modeli, które chcę mieć głosów z (strona w tym przykładzie) Stworzyłem VoteableTrait, który ma the votes() morphMany method and scope Próbuję dostać się do pracy. Zakres dodawałby sumę wszystkich głosów należących do określonego modelu i porządkował modele macierzyste według sumy. Zakres jako Próbowałem:

public function scopeWithVotesTrait($query) 
{ 
    return $query->with(['votes' => function($q){ 
     $q->select(\DB::raw("SUM(vote) AS votes"), 'voteable_id')->first(); 
    }]); 
} 

Ale z tym nie mogę orderby jak laravel wykona 2 różne zapytania, po jednym dla modelu dominującego i jeden dla głosów wydaje. Efektem Page :: withVotesTrait() -> pierwszy() umieszcza głosów w tablicy:

{ 
"id": 1, 
    "votes": [ 
    { 
     "votes": "-1", 
     "voteable_id": 1 
    } 
    ] 
} 

Innym pomysłem było to, aby przeprowadzić dołączyć zamiast -> z() tak:

public function scopeWithVotesTrait($query, $model, $table) 
{ 
    return $query->join('votes', function($join) use($model, $table) 
    { 
     $join->on('votes.voteable_id', '=', $table . '.id') 
      ->where('votes.voteable_type', '=', $model); 
    })->select('*', \DB::raw('sum(vote) as votes')) 
    ->orderBy('votes')->groupBy($table . '.id'); 
} 

Ale jeśli muszę ręcznie wstawić model $ ("App \ ParentModel") i $ table ("parent_models") za każdym razem, gdy używam zakresu, ten rodzaj bije w celu umieszczenia go w funkcji.

Czy istnieje sposób na sprawne zamówienie przez sumę głosów w moim pierwszym przykładzie zakresu? Czy istnieje jakaś statyczna metoda, którą można wywołać z Modelu wymownego, który zwróci nazwę modelu i jedną dla tabeli modelu, aby drugi przykład zadziałał?

Jakieś inne pomysły, jak stworzyć zakres, w którym dołączana byłaby suma wszystkich głosów do modelu macierzystego?

Odpowiedz

4

Mam go do pracy z drugim przykładem przy użyciu łączyć. Eloquent \ Model ma statyczną metodę getTable(), która zwraca nazwę tabeli modeli, więc mogę przekazać ją jako parametr modelu $ dynamicznie. I funkcja php get_class() zwróci przestrzeń nazw z nazwą klasy modelu macierzystego dla parametru $ model.

Prawidłowe zapytanie o to, co chciałem osiągnąć:

public function scopeWithVotesTrait($query) 
{ 
    return $query->leftJoin('votes', function($join) use($model, $table) 
    { 
     $join->on('votes.voteable_id', '=', $table . '.id') 
      ->where('votes.voteable_type', '=', $model); 
    })->addSelect('*', $table . '.id', \DB::raw('COALESCE(SUM(vote),0) as votes')) 
    ->groupBy($table . '.id')->orderBy('votes'); 
} 

Dodałem także COALESCE, co uczyni zwrot zapytań 0 jeśli nie znaleziono żadnych głosów. Jest tak, że orderBy jest zawsze poprawny.

Podałem także * i parent_table.id, aby wybrać wyciągi. Bez * zapytanie zwróci tylko to, co określimy w instrukcji select. I bez parent_table.id zapytanie nie zwróci żadnych modeli, które moglibyśmy zapytać metodami relacji (przykład: Model :: withVotesTrait() -> with ('some_other_child') nie doda some_other_child do wyniku).

Używam również leftJoin zamiast join, aby zawsze zwracał wszystkich rodziców, bez względu na liczbę głosów do niego przypisanych.