2016-02-16 9 views
6

У меня есть одно-много полиморфных отношений точно так же, как описано in documentation, за исключением того, что у меня есть голоса вместо фотографий и целое число голосов в таблице голосов. Как что:Область запроса Laravel 5.2 на полиморфные отношения

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

Модель Голосуйте имеет voteable метод:

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

Но для моделей, которые я хочу иметь голоса, присоединенные к (Страница в этом примере) я создал VoteableTrait, который имеет метод vote() morphMany и область действия, которую я пытаюсь получить. Объем добавит сумму всех голосов, принадлежащих определенной модели, и закажет родительские модели суммой. Область применения, как я попробовал:

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

Но с этим я не могу OrderBy, как Laravel выполняет 2 различных запросов, по одному для родительской модели и один для голосов, которым он кажется. В результате страницы :: withVotesTrait() -> первый() помещает голоса в массиве:

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

другая идея у меня была в том, чтобы выполнить объединение вместо -> с() так:

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

Но если мне придется вручную вводить $ model ('App \ ParentModel') и $ table ('parent_models') каждый раз, когда я использую область действия, это бьет цель положить ее в черту.

Итак, есть ли способ эффективно упорядочить по сумме голосов в моем первом примере сферы? Или существует какой-либо статический метод, который вы могли бы назвать от Eloquent Model, который вернет название модели, и один для таблицы моделей, чтобы сделать второй пример работы?

Любые другие идеи, как создать область, которая будет прикладывать сумму всех голосов к родительской модели и ее порядок?

ответ

4

У меня есть это для работы со вторым примером, использующим join. Eloquent \ Model имеет статический метод getTable(), который возвращает имя таблицы моделей, поэтому я могу передавать его как параметр $ model динамически. И функция php get_class() вернет пространство имен с именем класса родительской модели для параметра $ model.

Правильный запрос, для чего я хотел достичь:

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

Я также добавил COALESCE, что сделает возвращение запросов 0, если нет голосов не найдено. Это так, что orderBy всегда корректен.

Я также указал * и parent_table.id для выбора операторов. Без * запрос возвращает только то, что мы укажем в инструкции select. И без parent_table.id запрос не будет возвращать какие-либо модели, которые мы могли бы запросить с помощью методов отношений (пример: Model :: withVotesTrait() -> with ('some_other_child') не добавит some_other_child в результат).

Я также использовал leftJoin вместо того, чтобы присоединиться, чтобы он всегда возвращал всех родителей, независимо от количества голосов, связанных с ним.

Смежные вопросы