2013-07-11 19 views
6

Aktuell entwickeln wir eine sehr flexible und modulare Anwendung mit Zend Framework 2 und Doctrine 2. In dieser Anwendung gibt es mehrere Doctrine Entitäten, sagen wir zum Beispiel die Entität Product im Modul Products. Dieses Modul Products ist das Basis-/Standardmodul für das Produktmanagement.Lehre Vererbung ersatz

Wir möchten in der Lage sein, ein benutzerdefiniertes Products Modul für einen Kunden (XProducts) zu erstellen. Daher habe ich eine neue Entität erstellt, XProduct (mit einigen zusätzlichen Feldern), die Product erweitert. Wenn das benutzerdefinierte Modul aktiviert ist, möchte ich XProduct und sonst Product verwenden, aber nie zusammen (im selben Projekt).

Wenn ich beide Entitäten mit @Entity annotieren funktioniert es teilweise; zum Beispiel findAll funktioniert perfekt, aber find funktioniert nicht: die erstellte SELECT-Anweisung enthält die richtigen Spalten, aber die WHERE-Klausel ist falsch. Zum Beispiel:

SELECT t1.id AS id2, t1.name AS name3 FROM products t1 WHERE t0.id = ? 

denke, ich t1 steht für ProductX und t0 für Product aber ich kann nicht herausfinden, warum die Spalten korrekt sind (t1), aber die where-Klausel nicht (t0) ist.

Ich bin mir bewusst, dass Doctrine bietet Single Table Vererbung Vererbung zu erreichen, aber deshalb ist es notwendig, eine DiskriminatorColumn und die DiscriminatorMap auf der Basis/Standard-Entität zu definieren. Dies passt nicht zu uns, da wir unser Basis-/Standardmodul ändern müssen, wenn wir ein neues benutzerdefiniertes Modul für einen Kunden hinzufügen (und das ist nicht das, was wir wollen ...).

Hat jemand einen Hinweis auf die Behebung dieses Problems? Vielen Dank!

Antwort

7

Ich habe dieses Problem endlich behoben. Für alle Standard/Basisklassen habe ich eine zusätzliche abstrakte MappedSuperclass erstellt (wie Jurian Sluiman erwähnt).Zum Beispiel für eine bestimmte Product Einheit für einen Kunden muss ich folgendes:

  • AbstractProduct (enthält alle Standard/Basisfunktionalitäten)
  • Produkt (default/Basisklasse, die leer ist und sich AbstractProduct)
  • XProduct (die zusätzliche Funktionen für unsere Kunden enthält und erweitert AbstractProduct)

um die Probleme mit den Verbänden auf einem MappedSuperclass behebt ich auf die abstrakte Klasse beziehen, zum Beispiel: @ORM\OneToOne(targetEntity="ProductManagement\Entity\AbstractProduct")

mich dann Lehre der Verwendung EntityResolver (siehe http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/resolve-target-entity-listener.html) eine abstrakte Klasse (oder Schnittstelle) Zuordnung zu einer echten Einheit zur Karte (abhängig von der Konfiguration):

'entity_resolver' => array(
    'orm_default' => array(
     'resolvers' => array(
      // Note: Use only one 
      'ProductManagement\Entity\AbstractProduct' => 'ProductManagement\Entity\Product', // Default 
      'ProductManagement\Entity\AbstractProduct' => 'XProductManagement\Entity\XProduct', // For customer X 
     ) 
    ) 
) 

Auf diese Weise ich in der Lage bin außer Kraft zu setzen Meine Entitäten mit spezifischen Entitäten für meine Kunden, ohne das Standard/Basismodul und die Entitäten zu ändern (was genau das ist, wonach ich gesucht habe).

+0

Ich versuche den gleichen Ansatz, aber das Problem ist, dass die abstrakte Entity-Klasse (AbstractProduct) nicht in DQL-Abfragen verwendet werden kann. Laut dem [Handbuch] (http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html) sind zugeordnete Superklassen nicht abfragbar. Wie schreiben Sie Abfragen, die sowohl für Product als auch für XProduct funktionieren? – aimfeld

3

Wir verwenden dieses Muster ebenso wie es mit Doctrine am einfachsten zu arbeiten ist (obwohl es mit viel hässlichem Code viel besser gemacht werden kann). Nehmen Sie ein Beispiel unseres Moduls Portfolio, in dem eine Portfolio Instanz mehrere Instanzen Item einnehmen kann.

Wir arbeiten mit einer Portfolio Einheit, die von der zugeordneten Superklasse AbstractPortfolio erstreckt. Wenn ein Client ein spezielles Feld benötigt, erstellen wir einen ClientPortfolio, der die zugeordnete Superklasse erweitert, sodass alle Eigenschaften korrekt überladen werden.

Der Klassenname ist specified in the config und dieser String wird zum Beispiel in factory for the repository verwendet. Sie laden niemals das Portfolio-Repository, sondern laden immer das ClientPortfolio, auch wenn Sie die Repository-Klasse vom Service-Manager unter dem Namen des Standardportfolios anfordern.

Diese Methode funktioniert gut mit Repository-Funktionen like here (obwohl diese Klasse das Repository für eine Item und nicht die Portfolio ist). Ich würde die Vererbung einzelner Tabellen nicht verwenden, da Sie nicht mehrere Entitäten nebeneinander verwenden. Zumindest ist das unser Fall.

+1

Danke für Ihre Antwort. Eine MappedSuperclass klingt interessant, obwohl ich dann zusätzliche Klassen für alle Entitäten erstellen muss (Abstract und Standard/Basisklasse). Aber wenn es funktioniert; es ist in Ordnung :). Es gibt nur ein Problem: Eine MappedSuper-Klasse kann keine One-to-Many- und One-to-One-Beziehungen haben, und genau das möchte ich auch; Zum Beispiel hat eine 'ProductGroup' eine Elterneigenschaft, die sich selbst referenziert. Also ich denke, eine MappedSuperclass ist nicht möglich. –

+0

Ich bin jetzt auf meinem Handy, also kann ich es nicht einfach überprüfen, aber über dem Portfolio-Modul hat einen Portfolio-Container mit Elementen, die die richtigen Beziehungen (das ist eins zu viele). Überprüfen Sie das Github-Repository, dort sollte etwas vorhanden sein, damit dies funktioniert. –

+0

Die einzige Beziehung, die ich in Ihrem Modul finden kann, ist eine Viele-zu-Eins-Beziehung in AbstractItem zu Portfolio. Natürlich ist es auf der anderen Seite eine Eins-zu-Viele-Beziehung, aber in meiner Situation möchte ich die Beziehung auf dieser Seite definieren, die bei einer MappedSuperclass nicht funktioniert. –