2010-12-08 11 views
1

In meinem DB-Schema habe ich mehrere Tabellen, die sich auf eine Elterntabelle beziehen. Die „hässlich“ Art und Weise, die die Beziehung Sachen zu lösen würden die Abhängigkeiten manuell im Schema enthalten sein:Symfony und Doctrine Templates - Einrichten einer Eins-zu-viele-Beziehung

sfArea: 
    columns: 
    id: integer 
    name: string 

sfCity: 
    columns: 
    name: string   
    area_id: integer 
    relations: 
    Area: 
     class: sfArea 
     local: area_id 
     foreignType: many 
     foreignAlias: Cities 

sfItem: 
    columns: 
    name: string 
    area_id: integer 
    relations: 
    Area: 
     class: sfArea 
     local: area_id 
     foreignType: many 
     foreignAlias: Items 

jedoch jedes Mal, wenn ich eine Klasse hinzufügen, wird dem Bereich angebracht werden, ich muss hinzufügen die Relation und alle damit verbundenen Zeilen (copy/paste => future hell). Hier habe ich beschlossen, die Doctrine_Template zu verwenden, was mir das gleiche wie das zu erreichen erlaubt:

sfArea: 
    columns: 
    id: integer 
    name: string 

sfCity: 
    actAs: 
    AreaRelated: { foreignAlias: Cities } 
    columns: 
    name: string   

sfItem: 
    actAs: 
    AreaRelated: { foreignAlias: Items } 
    columns: 
    name: string 

und die Template-Klasse:

class AreaRelated extends Doctrine_Template 
{ 
    protected $_options = array(
     'foreignAlias' => '' 
    ); 

    public function setTableDefinition() 
    { 
     $this->hasColumn('area_id', 'integer'); 
    } 

    public function setUp() 
    { 
     $this->hasOne('sfArea as Area', array(
       'local' => 'area_id', 
       'foreign' => 'id', 
       'foreignType' => 'many', 
       'foreignAlias' => $this->_options['foreignAlias'] 
      ) 
     ); 
    } 
} 

Die Tabellen korrekt erzeugt werden und die Beziehung funktioniert in die Richtung $ sfCity-> Area. Die Beziehungen, die in der Klasse sfArea eingerichtet werden sollten, werden jedoch nicht erstellt ($ sf_area-> Cities gibt den Fehler "Unbekannte Datensatzeigenschaft/zugehörige Komponente" Cities "in" sfArea "" an).

Wie kann die andere Beziehung erstellt werden? Ich habe sogar versucht, dass (ohne Erfolg):

//... 
public function setUp() 
{ 
    $thisTable = $this->_table; 
    $areaTable = Doctrine::getTable("smArea"); 

    $thisTable->hasOne('smArea as Area', array(
      'local' => 'area_id', 
      'foreign' => 'id', 
      'foreignType' => Doctrine_Relation::MANY 
     ) 
    );   

    $areaTable->hasMany($thisTable->getOption('name') . ' as ' . $this->_options['foreignAlias'], array(
      'local' => 'id', 
      'foreign' => 'area_id', 
      'foreignType' => Doctrine_Relation::ONE 
     ) 
    );    
} 
+0

Hmm die Schema-Version sollte funktionieren Ich denke ... das einzige Problem, das ich sehe, ist, dass Ihre 'ForeignAlias' für jede Klasse anders sein sollten, dh' Cities' und 'Items'. Die hardcoded Version dagegen hat Probleme. – prodigitalson

+0

Hi, yep, korrigierte die Tippfehler (kein Tippfehler in meinem ursprünglichen Code, nur hier). Das ist mein großes Problem, um viel manuelle Kopie zu vermeiden, würde ich gerne die AreaRelated-Vorlage arbeiten lassen. –

+0

Scheint wie eine Menge Arbeit, um ein wenig Kopieren/Einfügen/Tippen zu vermeiden. Ich weiß nicht, meine Schemata ändern sich nicht so oft. – Nathan

Antwort

0

Leider glaube ich nicht, es gibt eine Möglichkeit, dies ohne mindestens einige zusätzliche Definitionen zu tun *. Eine Möglichkeit, dies zu tun, die minimale Ergänzungen erfordern würde wäre es, die Beziehungen auf dem Gebiet über eine Option zum Aufzählen:

Area: 
    options: 
    models_with_areas: [Cities, Items] 

legen Sie dann die Beziehungen in Area::setUp

public function setUp() 
{ 
    parent::setUp(); 
    $models = $this->getTable()->getOption('models_with_areas'); 
    foreach($models as $model) 
    { 
    $this->hasMany($model, array(
     'local' => 'id', 
     'foreign' => Doctrine_Inflector::tablize($model) . '_id' 
    )); 
    } 
} 

Natürlich ist ein solcher Ansatz unflexibel und wenn Sie wesentlich komplexere Logik oder Optionen wünschen, funktioniert das nicht so gut. Sie können die Beziehungen immer nur für den Bereich definieren, aber weiterhin Verhalten für die vielen Seiten der Beziehungen verwenden.

Im Gegensatz zu einigen anderen Antworten denke ich, dass dies ein vernünftiger Ansatz und möglicherweise eine gute Idee ist. Ein zentraler Grundsatz der Philosophie von Symfony/Doctrine ist Do not Repeat Yourself. Diese Lösung entspricht dieser Idee. Es bietet auch erhebliche Vorteile, wenn zwischen den Klassen, die AreaRelated sind, eine gemeinsame Logik vorhanden ist.

* Außer einem hässlichen: Sie könnten durch jede Tabelle iterieren und jede Tabelle finden, die die Vorlage AreaRelated hat. Dies würde erfordern, dass jede Tabelle jedes Mal instanziiert wird, wenn ein Bereichsdatensatz geladen wird, was wie eine absolut schreckliche Idee klingt.

-1

Ich glaube, Sie ein großes Modell Problem haben, was diese Art von hirearchy auf einer Datenbank nur werden Sie zu vielen Kopfschmerzen bekommen. Ich mache etwas Mäkel für eine große Website, die so etwas hat und die Hölle ist.

Mein Rat ist, denken Sie darüber nach und neu zu analysieren, wenn die Mietverwaltung wirklich in der Datenbank benötigt wird, oder vielleicht denken Sie in Objekten beim Modellieren einer relationalen Datenbank.

Mit den Informationen, die Sie in dem Beispiel City gegeben haben, scheint es "Kategorien" zu sein. Wenn Sie sie in eine Referenztabelle einfügen, könnte ein Bereich kategorisiert werden, wodurch die Code-Replikation minimiert wird. Eine Kategorie kann andere Beziehungen haben oder einfach eine große Tabelle mit vielen Feldern sein.

Also hier ist die Art von Modell i vorschlagen (Propel):

CategoryClass >> 
public function getObjectRepresentation() 
{ 
    return new $this->getModelClassName()($this); 
} 
[...] 

RealObjectRepresentation1 >> 
public function __construct(Category $category) 
{ 
    //Initialize proper object using category information 
} 
:

Area: 
    tableName: area_table 
    description: Area 
    columns: 
    id: 
    name: 
    category_id: 
     type: integer 
     foreignClass: Category 
     foreignReference: id 
     required: true 

Category 
    tableName: categor_table 
    description: An area specialization 
    columns: 
    id: 
    model_class_name: 
     type: varchar(255) 
     description: the model Class that will represent this piece of information 
    field1: 
    field2: 
    relation:1 

mode_class_name als Hinweis verwenden zu wissen, was mit Rohdaten zu tun, Sie so etwas wie tun könnten

So haben Sie DatabaseHirearchy zu PhpObjectHirearchy bewegt

Hoffe, das hilft in gewisser Weise, wenn Sie weitere Informationen benötigen, würde ich glücklich sein, zu helfen!

+1

Hallo, ich glaube, du hast das wahre Problem, das ich in der Frage geäußert habe, falsch verstanden. Darüber hinaus sind Stadt und Item wirklich völlig unbenannte Objekte, die viele Spalten haben, nicht nur einen Namen (und es gibt nicht nur 2, sondern 10 bis 15). Bei Ihrer Herangehensweise würde ich also einen Tisch mit 200 Spalten haben. Performance-mäßig, nicht ideal, aber ich denke, es könnte zu Fehlern bei der Auswahl der richtigen Spalten nach dem richtigen Objekt führen, wenn wir die Abfragen optimieren wollen. –

0

Bis jetzt, meine beste Schätzung ist es, den manuellen Weg in der Schemadatei zu machen. Da sich das Schema selten ändert, wie von Nathan erwähnt, denke ich, dass dies der beste Weg ist, es zu tun, wenn das Verhalten nicht implementiert werden kann (was ich als Nebenprojekt weiterhin versuchen werde). Der Vorteil des Behavior-Ansatzes besteht darin, dass er die Beziehungen zu einem bestimmten sehr zentralen Objekt automatisch und konsistent über alle Objekte erzeugen kann, die von diesem zentralen Objekt abhängen.

Ein anderes nützliches Beispiel, wo dies nützlich sein könnte, ist eine Multi-Site-Blog-Engine, in der alle Posts, Benutzer, Kategorien, Medien-Uploads, ... mit einem bestimmten Blog in Verbindung stehen.

sfArea: 
    columns: 
    id: integer 
    name: string 

sfCity: 
    columns: 
    name: string   
    area_id: integer 
    relations: 
    Area: 
     class: sfArea 
     local: area_id 
     foreignType: many 
     foreignAlias: Cities 

sfItem: 
    columns: 
    name: string 
    area_id: integer 
    relations: 
    Area: 
     class: sfArea 
     local: area_id 
     foreignType: many 
     foreignAlias: Items 
Verwandte Themen