Verstehe Relationen Nicht

Hallo,

kann mir jemand helfen, folgendes umzusetzen. Ist ja wahrscheinlich kein Yii Problem, sondern ein DB-Verständnisproblem. :-[

Ich habe Tabellen mit folgenden Fremdschlüsseln:

Tabelle Noten: Verlag_Id, Komponist_Id, Sammelheft_Id

Tabelle Sammelhefte: Verlag_Id

Tabelle Verlage

Tabelle Komponisten

Die Relationen im Model "Noten" habe ich so definiert:


public function relations()

{

        return array(

            'Komponist'=>array(self::BELONGS_TO, 'Komponisten', 'Komponist_Id'),

            'Verlag'=>array(self::BELONGS_TO, 'Verlage', 'Verlag_Id'),

            'Sammelheft'=>array(self::BELONGS_TO, 'Sammelhefte', 'Sammelheft_Id'),

        );

}

Hier noch eine Relation aus dem Model "Sammelhefte":


public function relations()

{

        return array(

            'Verlag'=>array(self::BELONGS_TO, 'Verlage', 'Verlag_Id'),

        );

}



In der Tabelle Noten gibt es "normale" Datensätze (Einzelhefte) und solche, welche ein Stück aus einem Sammelheft darstellen.

Nun möchte ich eine Noten-Ausgabe in Tabellenform haben mit dem Namen des Verlages. Je nach Datensatz soll in dieser Spalte der Verlag aus der Tabelle "Noten" bzw. aus der Tabelle "Sammelheft" stehen.

Folgende Methode im Model Noten liefert mir eine Ausgabe "Verlag", in der jeweils der Verlag aus der richtigen Tabelle stammt:


public function getVerlag() {

    if ( $this->Sammelheft_Id > 0 ) $Verlag_Id = $this->Sammelheft->Verlag_Id;

    else $Verlag_Id = $this->Verlag_Id;

    $model = new Verlage;

    $data=$model->findByPk($Verlag_Id); 

    return $data->Name;

}

Der Verlag wird von GridView richtig angezeigt.

Jedoch eine Suche in dieser Spalte bringe ich nicht zustande.

Ich nehme an, dass mein Ansatz falsch ist und dass man gleich über die Relationen die richtigen Spalten bekommt. Kann man so etwas mit ActivRecords machen?

Danke für jeden Tipp

Ferdinand

Grundsätzlich kannst du, wenn du die Relation definiert hast, über folgende Syntax an den Verlag kommen:


$note->verlag->name

(wobei name ein Attribut aus der Tabelle Verlag wäre).

Näheres hierzu findest du auch unter: Definitive Guide to Yii. Den Guide kann ich nur wärmstens empfehlen, um ein Grundverständnis für Yii zu entwickeln.

Im GridView musst du ein wenig anders arbeiten. Da gibt es aber schon jede Menge Posts im Forum und Wiki-Artikel, zum Beispiel hier.

Hoffe, das hilft erstmal weiter.

Danke für die Hilfestellung.

Ich habe inzwischen das oben geschilderte Problem lösen können. Da die Tabelle Verlage über den Fremdschlüssel Verlag_Id sowohl mit der Tabelle Noten als auch mit der Tabelle Sammelhefte verbunden ist, war die Definition eines Alias nötig.

Wie das in Yii geht habe ich mit viel Suchen im Netz zusammengebracht. Hier der Code aus dem Noten Model:


public function search_normal() {

    $criteria=new CDbCriteria;

    $criteria->with = array('Komponist','Verlag','Sammelheft',

			    'Sammelheft.Verlag'=>array('alias'=>'Verlag_Sammelheft'),

			    'Sammelheft.Komponist'=>array('alias'=>'Komponist_Sammelheft'));

Aber auf diese Weise bekam ich immer noch nicht eine einzige Spalte, in der entweder der Komponist aus der Tabelle Noten oder der Komponist aus der Tabelle Sammelhefte steht.

Ich nehme an, dass ich diese Spalte mit Hilfe von PHP Code erzeugen hätte können. Ich habe aber einen anderen Ansatz gewählt. Ich habe eine MySQL Abfrage gebildet, die mit Hilfe der IF Funktion die gewünschte Komponisten Spalte ausgibt. Die Abfrage - mit phpMyAdmin getestet - schaut so aus:


SELECT n.Id, `Werk` , s.Titel, 

IF(s.Komponist_Id,CONCAT(k1.Vorname,' ',k1.Zuname),CONCAT(k.Vorname,' ',k.Zuname)) AS Komp

FROM `Noten` AS n

LEFT JOIN Komponisten AS k ON n.Komponist_Id = k.Id

LEFT JOIN Komponisten AS k1 ON s.Komponist_Id = k1.Id

...

Ich habe dann versucht, über die select Eigenschaft von CDbCriteria diese Abfrage in Yii zu erzeugen, was aber immer zu einem Error geführt hat, sinngemäß: Attribut IF existiert nicht …

Name_Komponist


$criteria->select = "*,

    IF(t.Komponist_ID>0,

    CONCAT(Komponist.Vorname,' ',Komponist.Zuname),

    CONCAT(Sammelheft.Komponist.Vorname,' ',Sammelheft.Komponist.Zuname)) AS Composer";

Dann bin ich auf die Idee gekommen, die joins direkt in die Eigenschaft join von CDbCriteria zu schreiben. Die with Eigenschaft habe ich weggelassen. Auf diese Weise funktioniert es jetzt. Hier der etwas aufwändige Code, der mir aber genau das liefert, was ich brauche. Die Spalte Name_Komponist wird aus zwei Spalten zusammengesetzt und ist sortierbar und es kann in dieser Spalte gesucht werden (mit GridView).


public function search_extended() {


    $criteria=new CDbCriteria;


    $criteria->select = "*,t.Id AS Id, 

			  IF (t.Komponist_Id,

			    CONCAT(k.Vorname,' ',k.Zuname),

			    CONCAT(k1.Vorname,' ',k1.Zuname)) AS Name_Komponist,

			  IF (t.Sammelheft_Id, s.Besetzung, t.Besetzung) AS Besetzung_Werk,

			  IF (t.Sammelheft_Id, s.Verlag_Nr, t.Verlag_Nr) AS Nr_Verlag,

			  IF (t.Sammelheft_Id, s.Reihe, t.Reihe) AS Reihe_Verlag,

			  IF (t.Sammelheft_Id, v1.Name, v.Name) AS Name_Verlag,

			  CONCAT (t.Anmerkung,' ',s.Anmerkung) AS Anmerkung_Werk,

			  s.Titel AS Titel_Sammelheft

	";


    $criteria->join = "LEFT JOIN Sammelhefte AS s ON Sammelheft_Id = s.Id

			LEFT JOIN Verlage AS v ON t.Verlag_Id = v.Id

			LEFT JOIN Verlage AS v1 ON s.Verlag_Id = v1.Id

			LEFT JOIN Komponisten AS k ON t.Komponist_Id = k.Id

			LEFT JOIN Komponisten AS k1 ON s.Komponist_Id = k1.Id";

Man kann sich das Ergebnis hier anschauen und ausprobieren:

Notenverwaltung Demoversion