2013-07-11 17 views
6

Obecnie opracowujemy bardzo elastyczną i modułową aplikację z Zend Framework 2 i Doctrine 2. W tej aplikacji znajduje się wiele jednostek Doctrine, na przykład powiedzmy jednostkę Product w module Products. Ten moduł Products jest podstawowym/domyślnym modułem do zarządzania produktem.Zastępstwo Dziedziczenie doktryny

Chcemy być w stanie stworzyć niestandardowy moduł Products dla klienta (XProducts). Dlatego stworzyłem nowy podmiot, XProduct (z kilkoma dodatkowymi polami), który rozciąga się na Product.

Więc jeśli moduł niestandardowy jest włączony, chcę użyć XProduct i jeszcze Product, ale nigdy razem (w tym samym projekcie).

Jeśli dodaję dwie jednostki z @Entity, to działa częściowo; na przykład findAll działa idealnie, ale find nie działa: utworzona instrukcja SELECT zawiera poprawne kolumny, ale klauzula WHERE jest niepoprawna. Na przykład:

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

Chyba t1 podpórek ProductX i t0 dla Product ale nie mogę zrozumieć, dlaczego kolumny są prawidłowe (t1), ale gdy klauzula nie jest (t0).

Jestem świadomy, że Doctrine zapewnia dziedziczenie pojedynczej tabeli w celu osiągnięcia dziedziczenia, dlatego konieczne jest posiadanie kolumny DiscriminatorColumn i zdefiniowanie DiscriminatorMap w jednostce podstawowej/domyślnej. To nam nie pasuje, ponieważ musimy zmienić nasz moduł podstawowy/domyślny, jeśli dodamy nowy moduł niestandardowy dla klienta (a tego nie chcemy ...).

Czy ktoś ma pojęcia, jak rozwiązać ten problem? Dzięki!

Odpowiedz

7

Ostatecznie naprawiłem ten problem. Dla wszystkich domyślnych/klasy bazowej stworzyłem dodatkową abstrakcyjną klasę MappedSuper (jak wspomniał Jurian Sluiman).Na przykład dla konkretnego Product podmiotu dla klienta muszę następujące:

  • AbstractProduct (zawiera wszystkie funkcje default/baza)
  • produkt (klasa default/baza, która jest pusta i rozciąga AbstractProduct)
  • XProduct (który zawiera dodatkowe funkcjonalności dla naszych klientów i rozciąga AbstractProduct)

aby rozwiązać problemy ze stowarzyszeniami na MappedSuperclass odnoszę się do abstrakcyjnej klasy, na przykład: @ORM\OneToOne(targetEntity="ProductManagement\Entity\AbstractProduct")

Następnie używać doktryny EntityResolver (patrz http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/resolve-target-entity-listener.html) mapować klasy abstrakcyjnej (lub Interface) stowarzyszenie do realnego podmiotu (w zależności od konfiguracji):

'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 
     ) 
    ) 
) 

W ten sposób jestem w stanie przesłonić moje podmioty z określonymi podmiotami dla moich klientów, bez zmiany domyślnego/podstawowego modułu i encji (dokładnie to, czego szukałem).

+0

Próbuję tego samego podejścia, ale problem polega na tym, że klasa abstrakcji (AbstractProduct) nie może być używana w kwerendach DQL. Zgodnie z [podręcznikiem] (http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html) zmapowane klasy nadrzędne nie są zdolne do przetwarzania zapytań. Jak piszesz zapytania, które działają zarówno w produkcie, jak i w XProduct? – aimfeld

3

Korzystamy z tego wzoru, jak również z Doctrine, z którym najłatwiej się pracuje (chociaż można go znacznie usprawnić za pomocą wielu brzydkich kodów). Weź przykład naszego modułu Portfolio, w którym instancja Portfolio może zająć wiele instancji Item.

Współpracujemy z jednostką Portfolio, która rozciąga się od odwzorowanej nadklasy AbstractPortfolio. Jeśli mamy klienta wymagającego specjalnego pola, tworzymy ClientPortfolio, rozszerzając zmapowaną nadklasę, aby poprawnie przeciążyć wszystkie właściwości.

Nazwa klasy to specified in the config, a ten ciąg jest używany na przykład w postaci factory for the repository. Nigdy nie ładujesz repozytorium Portfolio, ale zawsze ładuj ClientPortfolio nawet, gdy zażądasz repozytorium od menedżera usług pod nazwą domyślnego portfela.

Ta metoda może działać poprawnie z funkcjami repozytorium like here (chociaż ta klasa jest repozytorium dla Item, a nie dla Portfolio). Nie używałbym dziedziczenia pojedynczej tabeli, ponieważ nie używasz wielu obiektów poza sobą. Przynajmniej tak jest w naszym przypadku.

+1

Dzięki za odpowiedź. Klasa MappedSuper brzmi interesująco, chociaż muszę utworzyć dodatkowe klasy dla wszystkich encji (klasa abstrakcyjna i domyślna/podstawowa). Ale jeśli to działa; w porządku :). Jest tylko jeden problem: klasa MappedSuperclass nie może mieć relacji jeden do wielu i jeden do jednego, i to jest dokładnie to, co ja nie; na przykład grupa 'ProductGroup' ma odwołanie do właściwości macierzystej. Myślę więc, że używanie klasy MappedSuper nie jest możliwe. –

+0

Jestem teraz na telefonie komórkowym, więc nie mogę go łatwo sprawdzić, ale powyżej modułu portfolio znajduje się kontener portfela z elementami w nim, mającymi właściwe relacje (to jeden do wielu). Sprawdź repozytorium Github, tam powinno być coś, co sprawi, że to zadziała. –

+0

Jedyną relacją jaką mogę znaleźć w twoim module jest relacja Wiele-To-Jeden w AbstractItem do Portfolio. Oczywiście z drugiej strony jest to relacja Jeden do Wielu, ale w mojej sytuacji chcę zdefiniować relację po tej stronie, która nie zadziała w klasie MappedSuper. –