2013-06-24 7 views
0

У меня есть таблица «примеров», таблица «теги» и промежуточная таблица «examples_has_tags». Таким образом, один пример может иметь некоторые теги, и один тег может принадлежать некоторым примерам.Laravel 4 filter relationship

В index.php Я показываю все примеры и список тегов.

$examples = Example::with('tags')->where('public', true)->get(); 

$tags = Tag::all(); 

return View::make('index')->with('examples', $examples) 
          ->with('tags',  $tags); 

Работает отлично. Но как я могу фильтровать примеры по имени тега? Я нашел что-то в stackoverflow: вы должны создать статический метод в классе Example, который возвращает то, что мне нужно. Но я запутался в отображении данных. В приведенном выше коде я показываю это как:

@foreach ($examples as $example) 
     <div class="widgetbox"> 
      <h4 class="widgettitle">{{ $example->name }}</h4> 
      <div class="widgetcontent"> 
       {{ $example->body }} 
       <div class="tags-list"> 
        @foreach ($example->tags as $tag) 
         <span class="label label-info tag">{{ $tag->name }}</span> 
        @endforeach 
       </div> 
      </div> 
     </div> 
    @endforeach 

Есть ли простой способ сделать это? Я нашел кое-что о коллекции фильтрации, но нет примеров

обновление

я нашел следующее решение:

$examples = $examples->filter(function($example) { 
     $tags = $example->tags->toArray(); 
     foreach ($tags as $tag) { 
      if ($tag["name"] == Input::get('tag')) return true; 
     } 
     return false; 
    }); 

Update2

Пытался сделать это без фильтрации PHP, но я не могу получить теги, которые относятся к примеру:

$tagId = Tag::where('name', '=', Input::get('tag'))->first()->id; 

     $examples = Example::with('tags') 
          ->join('examples_has_tags', 'examples_has_tags.example_id', '=', 'examples.id') 
          ->where('examples_has_tags.tag_id', '=', $tagId)->get(); 

$ примеры не содержит список тегов (пусто на самом деле)

+0

Как насчет моего альтернативного подхода (in_array), можете ли вы его проверить? –

+0

Не работает, $ example-> tags-> toArray() возвращает не просто массив ("tagName1", "tagName2" ...), так что ... Я пробовал array_pluck, но безуспешно (не знаю, почему id didn я работаю для меня). – Victor

+0

Работает ли ваше решение? –

ответ

0

Вы можете сделать это следующим образом (Eager Loading)

Модель: (пример)

class Example extends Eloquent { 
    public function tags() 
    { 
     return $this->hasMany('Tag'); 
    } 
} 

сейчас запрос:

$examples = Example::with(array('tags' => function($query) 
{ 
    $query->where('name', '=', 'someName'); 
}))->get(); 

Update:

$examples = $examples->filter(function($example) { 
    $tags = $example->tags->toArray(); 
    return in_array(Input::get('tag'), $tags) ?: FALSE; 
}); 
+0

Как я понимаю, я получу все примеры, и в каждом примере у меня будут отфильтрованные теги.Но это не то, что я пытаюсь получить - я хочу сам фильтровать список примеров. Я думаю, что я уже пробовал ваше решение, но я проверю через пару часов, спасибо – Victor

+0

Возможно, я неправильно понял, в любом случае, приветствую :-) –

+0

Посмотрите на мое решение в своем посте (я его обновил). Похоже, что это работает – Victor

0

Что вы должны сделать, это создать объединение, а затем создать где положение о вещах вы хотите. В зависимости от того, как вы хотите, чтобы фильтровать по тегам, вы можете сделать что-то вроде этого:

Первый принести действительные идентификаторы тегов:

$tagIDs = array_pluck(Tag::whereIn('name', array(
    'tag1', 
    'tag2', 
    'tag3', 
))->toArray(), 'id'); 

Затем процеживают примеры по tag_id:

return Example::select('examples.*') 
    ->join('examples_has_tags', 'examples.id', '=', DB::raw('examples_has_tags.example_id')) 
    ->whereIn(DB::raw('examples_has_tags.tag_id'), $tagIDs) 
    ->get(); 

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

+0

Что касается моего решения (я обновил сообщение)? Похоже, это работает – Victor

+1

Да, это ваше решение должно работать. Однако есть разница. Вы делаете фильтрацию с помощью PHP. Это медленнее, чем механизм БД, потому что он не оптимизирован для этого. Кроме того, вы извлекаете ВСЕ примеры в свой скрипт, а затем запускаете фильтрацию. Представьте, что у вас есть база данных с 1.000.000 записями ... она станет очень медленной. Если вы позволите движку БД выполнить фильтрацию, вы не будете (действительно) иметь эту проблему. – DerLola

+0

Я думаю, вы правы, но как я могу получить список тегов для каждого примера? Посмотрите update2 в моем посте. Поскольку я фильтрую только один тег, я немного изменил запрос, и я не использую DB :: raw, поскольку он работает без этого. Я получаю правильные примеры, но я, когда прокручиваю их, и пытаюсь отобразить список тегов для каждого примера (например, @foreach ($ example-> tags as $ tag), массив тегов пуст ... – Victor