2016-08-08 41 views
1

Ich bin neu bei yii2. Ich habe die Dokumentation und einige Antworten auf SOF gelesen, aber ich kann noch nicht mit Beziehungen in yii2 arbeiten. Ich bin in der Lage, raw mysql-Abfrage für das Problem zu erstellen, aber ich weiß nicht, wie Sie die gleiche Abfrage mit yii2 Beziehungen erstellen. Ich bin verwirrt mit Via, JoinWith und einigen Schlüsselkonzepten. Ich werde das Problem so anschaulich wie möglich machen. Ich habe vier Modelle.Yii2 Join Beziehungen für mehrere Tabellen

Category, CategoryNews, NewsTags, Tags 

category table - cat_id, cat_name 
news_category table - nc_id, nc_cat_id, nc_news_id 
news_tags table - nt_id, nt_news_id, nt_tag_id 
tags table - tag_id, tag_name 

Was ich brauche, ist Tags Modellobjekt für jede Kategorie, die für jede Kategorie ich brauche ist es, alle Nachrichten-Tags zu dieser Kategorie gehören. Die Anfrage stammt von gridview. Die erzeugten Beziehungen sind:

Category Model: 

public function getNewsCategory() 
{ 
    return $this->hasMany(NewsCategory::className(), ['nc_cat_id' => 'cat_id']); 
} 

NewsCategory Model: 

public function getNcNews() 
{ 
    return $this->hasOne(News::className(), ['news_id' => 'nc_news_id']); 
} 

public function getNcCat() 
{ 
    return $this->hasOne(Category::className(), ['cat_id' => 'nc_cat_id']); 
} 

NewsTags Model: 

public function getNtNews() 
{ 
    return $this->hasOne(News::className(), ['news_id' => 'nt_news_id']); 
} 

public function getNtTag() 
{ 
    return $this->hasOne(Tags::className(), ['tag_id' => 'nt_tag_id']); 
} 

News Model: 

public function getNewsCategory() 
{ 
    return $this->hasMany(NewsCategory::className(), ['nc_news_id' => 'news_id']); 
} 

public function getNewsTags() 
{ 
    return $this->hasMany(NewsTags::className(), ['nt_news_id' => 'news_id']); 
} 

Tags Model: 

public function getNewsTags() 
{ 
    return $this->hasMany(NewsTags::className(), ['nt_tag_id' => 'tag_id']); 
} 

dh. Jede Kategorie enthält mehrere Nachrichten und jede Nachricht enthält mehrere Tags und ich brauche alle Tags für jede Kategorie. Genauer gesagt, in der Gridview brauche ich alle Kategorien und eine Spalte mit allen Tags zu diesen Kategorien. Bitte helfen Sie !!

Antwort

1

Sie können die Deklaration von Modellen für Junction-Tabellen unter Verwendung der viaTable-Syntax für many-to-many Relationen vermeiden. Dann wird Ihr Code nur drei Modelle (Category, News und Tag) enthalten und alles wird viel einfacher.

Ihr Code für AR-Modelle und Beziehungen konnten sieht wie folgt aus:

public class Category extends ActiveRecord 
{ 
    public function getNews() 
    { 
     return $this->hasMany(News::className(), ['id' => 'news_id']) 
      ->viaTable('news_category_table', ['category_id' => 'id']); 
    } 
} 

public class News extends ActiveRecord 
{ 
    public function getCategories() 
    { 
     return $this->hasMany(Category::className(), ['id' => 'category_id']) 
      ->viaTable('news_category_table', ['news_id' => 'id']); 
    } 

    public function getTags() 
    { 
     return $this->hasMany(Tags::className(), ['id' => 'tag_id']) 
      ->viaTable('news_tags_table', ['news_id' => 'id']); 
    } 
} 

public class Tag extends ActiveRecord 
{ 
    public function getNews() 
    { 
     return $this->hasMany(News::className(), ['id' => 'news_id']) 
      ->viaTable('news_tags_table', ['tag_id' => 'id']); 
    } 
} 

Diese Beziehungen Sie in link und unlink Funktionen verwenden können (Zeilen in Tabellen Kreuzung von Yü in Hintergrund wird verwaltet). Aber denken Sie daran, dass Sie TRUE als zweiter param in unlink() verwenden sollten Zeilen in Verknüpfungstabelle zu entfernen:

$article = new News(); 
$tag = new Tag();  
$tag->save(); 
$article->link('tags', $tag); 
$article->link('caterories', $category); 

oder umgekehrt

$tag->link('news', $article); 
$category->link('news', $article); 

Um alle Tags in bestimmten Kategorie erhalten Sie folgende Funktion erklären können in Category Klasse:

public function getTags() 
{ 
    return Tags::find() 
     ->joinWith(['news', 'news.categories C']) 
     ->where(['C.id' => $this->id]) 
     ->distinct(); 
} 

Dies wird als Beziehung Abfrage arbeiten, und Sie es alsverwenden können 210 oder als $category->getTags()->count() oder auf andere Weise (aber nicht in link und unlink Funktionen).

P.S. Um das mitgelieferte Beispiel in Ihrem Code zu verwenden, sollten Sie zuerst Namen ändern, weil ich Singularform für AR-Klassennamen (Tag) und kurze Notation für Primär- und Fremdschlüssel (id, tag_id usw.) verwendet habe. Und ich würde Ihnen empfehlen, einen solchen Benennungsansatz in Ihrer Code- und DB-Struktur zu verwenden.

P.P.S. Dieser Beispielcode wurde nicht getestet, also sei vorsichtig :)