2013-06-06 3 views
0

Я хочу отфильтровать свой запрос ORM с помощью двух отношений «многие-ко-многим»: регионов и рабочих мест.Laravel 4 - paginate with the filter Eloquent ORM

Мне нужно paginate, но $ final-> paginate() невозможно, но я не знаю, почему.

Как смягчены мой код для использования -> постраничной() и не Paginatore :: не делают

/* sélectionne tout les candidats qui sont disponnibles, et qui ont une date inférieure 
    * à celle configuré 
    */ 
    $contacts = Candidate::with('regions', 'jobs') 
          ->where('imavailable', '1') 
          ->where('dateDisponible', '<=', $inputs['availableDate']) 
          ->get(); // ta requete pour avoir tes contacts, ou par exemple tu fais un tri normal sur tes regions. Il te reste à trier tes jobs. 

    // ajoute un filtre, pour n'afficher que ceux qui reponde true aux 2 test dans les foreachs 
    $final = $contacts->filter(function($contact) use($inputs) { 

     // par défaut ils sont false 
     $isJob = false; 
     $isRegion = false; 

     // test que le candidat à l'un des jobs recherché par l'entreprise 
     foreach($contact->jobs as $job) { 

      // si le job id du candidat est dans la liste, alors on retourne true 
      if(in_array($job->id, $inputs['job'])) { 

       $isJob = true; 
      } 
     } 
     // test que le candidat accepte de travailler dans l'une des régions echerchées 
     foreach($contact->regions as $region) { 

      // si region id du candidat est dans la liste, alors on retourne true 
      if(in_array($region->id, $inputs['region'])) { 

       $isRegion = true; 
      } 
     } 

     // si les 2 renvoie true, alors nous returnons le candidat à la vue 
     if($isRegion && $isJob){ 

      return true; 
     } 
     else{ 

      return false; 
     } 
    }); 

    // converti le resultat en tableau pour l'importer dans le Paginator 
    $finalArray = $final->toArray(); 

    // calcule le nombre de candidat dans le tableau 
    $finalCount = count($finalArray); 

    // créer le pagniate manuellement, car on ne peux faire $final->paginate(20) 
    $paginator = Paginator::make($finalArray, $finalCount, 2); 

    // return la liste des candidats 
    return $paginator; 

Спасибо.

ответ

1

Хорошо, третий раз это очарование:

Первый, ваша проблема производительности происходит от STRUC базы данных но не запрос.

Вам необходимо добавить следующие показатели, чтобы получить серьезный прирост производительности:

ALTER TABLE `candidate_region` ADD INDEX `REGION_ID` ( `region_id`) 
ALTER TABLE `candidate_region` ADD INDEX `CANDIDATE_ID` ( `candidate_id`) 
ALTER TABLE `candidate_job` ADD INDEX `JOB_ID` ( `job_id`) 
ALTER TABLE `candidate_job` ADD INDEX `CANDIDATE_ID` ( `candidate_id`) 

Сводные таблицы с соответствующими индексами лучше работать.

Второй, это (чистый) SQL-запрос вы хотите запустить:

SELECT * 
FROM candidates 
INNER JOIN candidate_region 
ON candidates.id = candidate_region.candidate_id 
INNER JOIN candidate_job 
ON candidates.id = candidate_job.candidate_id 
WHERE imavailable = 1 AND dateDisponible <= '2013-12-31' AND region_id IN (2,3,4,43,42) AND job_id IN (1,2,5,8) 

С учетом указанных выше показателей, этот запрос выполняется под вторым. Без индексов он был отключен на моей машине.

Третий, это то, что этот запрос должен выглядеть в Fluent:

DB::table('candidates') 
    ->join('candidate_region', 'candidates.id', '=', 'candidate_region.candidate_id'); 
    ->join('candidate_job', 'candidates.id', '=', 'candidate_job.candidate_id'); 
    ->whereIn('candidate_region.region_id',$inputs['region']) 
    ->whereIn('candidate_job.job_id',$inputs['job']) 
    ->where('imavailable', '1') 
    ->where('dateDisponible', '<=', $inputs['availableDate']) 
    ->get(); // Or paginate() 

Это проверялось, но должно работать как есть или с незначительными изменениями.

Наслаждайтесь!

+0

Спасибо, очень, но как добавить 'ADD INDEX' с миграцией laravel, это невозможно? – timothylhuillier

+0

'$ table-> index ('state');' http://laravel.com/docs/schema#adding-indexes –

+0

oups, я этого не видел. Спасибо – timothylhuillier

0

Почему бы вам просто не заменить свой фильтр() двумя простыми простыми whereIn()?

$contacts = Candidate::with('regions', 'jobs') 
         ->where('imavailable', '1') 
         ->where('dateDisponible', '<=', $inputs['availableDate']) 
         ->whereIn('job_id', $inputs['job']) 
         ->whereIn('region_id', $inputs['region']) 
         ->get(); 

Таким образом, вы должны быть в состоянии использовать paginate(), как вы хотели.

+0

Поскольку я использую 2 шарнирные: Регионы и Работа "candidate_region: идентификатор, candidate_id, Region_ID" и "candidate_job: идентификатор, candidate_id, job_id" – timothylhuillier

+0

Кажется, вы можете» t use where() с отношениями с загружаемой загрузкой [см. источник] (http: // stackoverflow.com/questions/14621943/laravel-how-to-use-where-conditions-for-relations-column) Но эта же ссылка также показывает вам, как вы могли бы сделать это без нетерпеливой загрузки (:: with (...)) и используя общедоступный метод для объединения() соответствующих сводных таблиц. Если вы передадите свой регион и задание в качестве параметров для этого метода и выполните два INNER JOINs, вы должны получить отфильтрованные данные. –

+0

I d'ont underdstand, извините. Я должен включить в мой ORM 2 соединения()? – timothylhuillier

0

Это выстрел в темноте (у меня нет настройки laravel здесь), но он должен работать в значительной степени как есть.

Изменить модель Candidate добавить новый метод, который делает соединяющую и фильтрации:

class Candidate extends Eloquent { 

    /* Le code existant de ton modèle "Candidate" est ici */ 


    /* Nouvelle méthode qu'on ajoute au modèle pour le filtrer par region et job */ 

    public static function forRegionsAndJobs($regions, $jobs) 
    { 
     return static::join(
     'candidate_region', 
     'candidates.id', '=', 'candidate_region.candidate_id' 
    )->whereIn('region_id', $regions) 
     ->join(
     'candidate_job', 
     'candidates.id', '=', 'candidate_job.candidate_id' 
    )->where('job_id', $jobs); 
    } 
} 

Тогда вы можете назвать эту модель с фильтром, и разбиваться, как вы хотите:

$contacts = Candidate::forRegionsAndJobs($inputs['region'], $inputs['job']) 
          ->where('imavailable', '1') 
          ->where('dateDisponible', '<=', $inputs['availableDate']) 
          ->paginate(25); 
+0

Спасибо, это очень хорошо, но resquest занимает 13/20 секунд и не возвращает рабочие места и регионы – timothylhuillier

+0

Вы можете добавить свой -> с (...) назад и получить свои отношения, но это добавит больше времени на запрос и дважды читайте эти таблицы из БД. Вот почему мне не нравятся модели и Eloquent, написание этого запроса в Fluent или pure SQL было бы намного проще и быстрее работать. –

+0

Спасибо, я пытаюсь сделать Свободный запрос. Это не работает или запрос занимает 13 сек. 'DB :: table ('кандидаты') -> join ('кандидаты', функция ($ join) {$ join-> on ('кандидаты.ид, '=', 'candid_region.candidate_id'); }) -> гдеIn ('кандидаты.регион_ид', $ входы ['region']) -> join ('regions', function ($ join) { $ join_> on ('regions.id', '=', 'candid_region.region_id'); }) -> гдеIn ('кандидат_job.job_id', $ input ['job']) -> где (' imavailable ',' 1 ') -> get(); ' – timothylhuillier