Doctrine2: Referans tablosunda fazladan sütunlarla çoktan çoğa işlemenin en iyi yolu


282

Doctrine2'de çoktan çoğa ilişkilerle çalışmanın en iyi, en temiz ve en basit yolunun ne olduğunu merak ediyorum.

Diyelim ki Metallica'dan Master of Puppets gibi birkaç parçalı bir albümümüz var . Ancak, bir parçanın, Metallica'nın Pil ile olduğu gibi bir albümden daha fazlasında görünebileceğini unutmayın. - üç albüm bu parçayı içeriyor.

Yani ihtiyacım olan, bazı ek sütunları (belirtilen albümdeki parçanın konumu gibi) üçüncü tabloyu kullanarak, albümler ve parçalar arasında çoktan çoğa ilişki. Aslında, Doctrine'in belgelerinde belirtildiği gibi, bu işlevselliği elde etmek için çift bire çok ilişki kullanmak zorundayım.

/** @Entity() */
class Album {
    /** @Id @Column(type="integer") */
    protected $id;

    /** @Column() */
    protected $title;

    /** @OneToMany(targetEntity="AlbumTrackReference", mappedBy="album") */
    protected $tracklist;

    public function __construct() {
        $this->tracklist = new \Doctrine\Common\Collections\ArrayCollection();
    }

    public function getTitle() {
        return $this->title;
    }

    public function getTracklist() {
        return $this->tracklist->toArray();
    }
}

/** @Entity() */
class Track {
    /** @Id @Column(type="integer") */
    protected $id;

    /** @Column() */
    protected $title;

    /** @Column(type="time") */
    protected $duration;

    /** @OneToMany(targetEntity="AlbumTrackReference", mappedBy="track") */
    protected $albumsFeaturingThisTrack; // btw: any idea how to name this relation? :)

    public function getTitle() {
        return $this->title;
    }

    public function getDuration() {
        return $this->duration;
    }
}

/** @Entity() */
class AlbumTrackReference {
    /** @Id @Column(type="integer") */
    protected $id;

    /** @ManyToOne(targetEntity="Album", inversedBy="tracklist") */
    protected $album;

    /** @ManyToOne(targetEntity="Track", inversedBy="albumsFeaturingThisTrack") */
    protected $track;

    /** @Column(type="integer") */
    protected $position;

    /** @Column(type="boolean") */
    protected $isPromoted;

    public function getPosition() {
        return $this->position;
    }

    public function isPromoted() {
        return $this->isPromoted;
    }

    public function getAlbum() {
        return $this->album;
    }

    public function getTrack() {
        return $this->track;
    }
}

Örnek veri:

             Album
+----+--------------------------+
| id | title                    |
+----+--------------------------+
|  1 | Master of Puppets        |
|  2 | The Metallica Collection |
+----+--------------------------+

               Track
+----+----------------------+----------+
| id | title                | duration |
+----+----------------------+----------+
|  1 | Battery              | 00:05:13 |
|  2 | Nothing Else Matters | 00:06:29 |
|  3 | Damage Inc.          | 00:05:33 |
+----+----------------------+----------+

              AlbumTrackReference
+----+----------+----------+----------+------------+
| id | album_id | track_id | position | isPromoted |
+----+----------+----------+----------+------------+
|  1 |        1 |        2 |        2 |          1 |
|  2 |        1 |        3 |        1 |          0 |
|  3 |        1 |        1 |        3 |          0 |
|  4 |        2 |        2 |        1 |          0 |
+----+----------+----------+----------+------------+

Şimdi bunlarla ilişkili albümlerin ve parçaların bir listesini görüntüleyebilirim:

$dql = '
    SELECT   a, tl, t
    FROM     Entity\Album a
    JOIN     a.tracklist tl
    JOIN     tl.track t
    ORDER BY tl.position ASC
';

$albums = $em->createQuery($dql)->getResult();

foreach ($albums as $album) {
    echo $album->getTitle() . PHP_EOL;

    foreach ($album->getTracklist() as $track) {
        echo sprintf("\t#%d - %-20s (%s) %s\n", 
            $track->getPosition(),
            $track->getTrack()->getTitle(),
            $track->getTrack()->getDuration()->format('H:i:s'),
            $track->isPromoted() ? ' - PROMOTED!' : ''
        );
    }   
}

Sonuçlar beklediğim, yani: parçalarını uygun sırayla ve yükseltilmiş olarak tanıtılan olarak işaretlenmiş albümlerin bir listesi.

The Metallica Collection
    #1 - Nothing Else Matters (00:06:29) 
Master of Puppets
    #1 - Damage Inc.          (00:05:33) 
    #2 - Nothing Else Matters (00:06:29)  - PROMOTED!
    #3 - Battery              (00:05:13) 

Yani ne yanlış?

Bu kod neyin yanlış olduğunu gösterir:

foreach ($album->getTracklist() as $track) {
    echo $track->getTrack()->getTitle();
}

Album::getTracklist()AlbumTrackReferencenesneler yerine bir Tracknesne dizisi döndürür . Proxy yöntemleri oluşturamıyorum neden her ikisi de neden olur Albumve yöntemi Trackolurdu getTitle()? Album::getTracklist()Yöntem içinde bazı ekstra işlemler yapabilirdim ama bunu yapmanın en basit yolu nedir? Böyle bir şey yazmaya zorlandım mı?

public function getTracklist() {
    $tracklist = array();

    foreach ($this->tracklist as $key => $trackReference) {
        $tracklist[$key] = $trackReference->getTrack();

        $tracklist[$key]->setPosition($trackReference->getPosition());
        $tracklist[$key]->setPromoted($trackReference->isPromoted());
    }

    return $tracklist;
}

// And some extra getters/setters in Track class

DÜZENLE

@beberlei proxy yöntemlerini kullanmanızı önerdi:

class AlbumTrackReference {
    public function getTitle() {
        return $this->getTrack()->getTitle()
    }
}

Bu iyi bir fikir olurdu ama ben her iki taraftan bu "referans nesnesi" kullanıyorum: $album->getTracklist()[12]->getTitle()ve $track->getAlbums()[1]->getTitle(), böylece getTitle()yöntem çağırma bağlamına göre farklı veriler dönmelidir.

Gibi bir şey yapmak zorunda kalacak:

 getTracklist() {
     foreach ($this->tracklist as $trackRef) { $trackRef->setContext($this); }
 }

 // ....

 getAlbums() {
     foreach ($this->tracklist as $trackRef) { $trackRef->setContext($this); }
 }

 // ...

 AlbumTrackRef::getTitle() {
      return $this->{$this->context}->getTitle();
 }

Ve bu çok temiz bir yol değil.


2
AlbumTrackReference ile nasıl başa çıkıyorsunuz? Örneğin $ album-> addTrack () veya $ album-> removeTrack ()?
Daniel

Bağlam hakkında yorum yaptığını anlamadım. Benim görüşümde veriler bağlama bağlı değildir. Yaklaşık $album->getTracklist()[12]bir AlbumTrackRefnesne, yani $album->getTracklist()[12]->getTitle()(proxy yöntemi kullanıyorsanız) her zaman şarkının başlığını dönecektir. Nesne olsa $track->getAlbums()[1]da Album, $track->getAlbums()[1]->getTitle()her zaman albümün başlığını döndürür.
Vinícius Fagundes

Başka bir fikir, AlbumTrackReferenceiki proxy yöntemi üzerinde kullanmaktır getTrackTitle()ve getAlbumTitle.
Vinícius Fagundes

Yanıtlar:


158

Doktrin kullanıcı posta listesinde benzer bir soru açtım ve gerçekten basit bir cevap aldım;

çoktan çoğa ilişkiyi bir varlık olarak düşünün ve sonra aralarında bire çok ve çoktan bir ilişkiye bağlı 3 nesneniz olduğunu fark edersiniz.

http://groups.google.com/group/doctrine-user/browse_thread/thread/d1d87c96052e76f7/436b896e83c10868#436b896e83c10868

Bir ilişkinin verileri olduğunda, artık bir ilişki yoktur!


Herkes bu yeni varlık bir yml şema dosyası olarak oluşturmak için öğreti komut satırı aracını nasıl alabilirim biliyor mu? Bu komut: app/console doctrine:mapping:import AppBundle ymlorijinal iki tablo için hala manyToMany ilişkisi oluşturun ve üçüncü tabloyu varlık olarak değerlendirmek yerine yok sayın:/
Stphane

foreach ($album->getTracklist() as $track) { echo $track->getTrack()->getTitle(); }@Crozin tarafından sağlanan ile arasındaki fark consider the relationship as an entitynedir? Sormak istediği şey, ilişkisel varlığı nasıl atlayacağımız ve kullanarak bir parçanın başlığını nasıl alacağınızforeach ($album->getTracklist() as $track) { echo $track->getTitle(); }
panda

6
"Bir ilişkinin verileri olduğunda, artık bir ilişki yoktur" Bu gerçekten aydınlatıcıydı. Bir varlık perspektifinden bir ilişki düşünemedim!
Soğan

İlişkinin zaten oluşturulmuş ve çoktan çoğa olarak kullanılmış olup olmadığı hakkında. Pek çoğumuzda fazladan alana ihtiyaç duyduğumuzu fark ettik, böylece farklı bir varlık yarattık. Sorun, mevcut verilerle ve aynı ada sahip mevcut bir tabloyla arkadaş olmak istemiyor. Bunu daha önce deneyen var mı?
tylerism

Merak edenler için: tablosu çalışırken (zaten var olan) çoktan çoğa birleştirilebilir bir Varlık oluşturmak, ancak çoktan çoğa sahip varlıkların yerine yeni varlık yerine bire çok uyarlanması gerekir. ayrıca dış arayüzler (eski çoktan çoğa alıcılar / pasifler) büyük olasılıkla uyarlanmalıdır.
Jakumi

17

$ Album-> getTrackList () 'de "AlbumTrackReference" varlıklarını geri alırsınız, peki Track ve proxy'den yöntem eklemeye ne dersiniz?

class AlbumTrackReference
{
    public function getTitle()
    {
        return $this->getTrack()->getTitle();
    }

    public function getDuration()
    {
        return $this->getTrack()->getDuration();
    }
}

Bu şekilde, tüm yöntemler sadece AlbumTrakcReference içinde proksiye edildiğinden, bir albümün parçalarını döngü ile ilgili diğer tüm kodların yanı sıra, döngünüz de önemli ölçüde basitleşir:

foreach ($album->getTracklist() as $track) {
    echo sprintf("\t#%d - %-20s (%s) %s\n", 
        $track->getPosition(),
        $track->getTitle(),
        $track->getDuration()->format('H:i:s'),
        $track->isPromoted() ? ' - PROMOTED!' : ''
    );
}

Btw AlbumTrackReference öğesini yeniden adlandırmalısınız (örneğin "AlbumTrack"). Açıkça sadece bir referans değil, aynı zamanda ek mantık da içerir. Muhtemelen bir albüme bağlı olmayan ancak promo-cd veya başka bir şeyle ulaşılabilen Parçalar da olduğundan daha temiz bir ayırmaya izin verir.


1
Proxy yöntemleri sorunu% 100'de çözmez (düzenlememi kontrol et). Btw You should rename the AlbumT(...)- iyi bir nokta
Crozin

3
Neden iki yönteminiz yok? AlbumTrackReference nesnesinde getAlbumTitle () ve getTrackTitle ()? Her ikisi de kendi alt nesnelerine proxy yapar.
beberlei

Amaç en doğal nesne API'sıdır. $album->getTracklist()[1]->getTrackTitle()kadar iyi / kötü $album->getTracklist()[1]->getTrack()->getTitle(). Ancak iki farklı sınıfa ihtiyacım var gibi görünüyor: biri albüm-> parça referansları için, diğeri parça-> albüm referansları için - ve bunu uygulamak çok zor. Muhtemelen bu şimdiye kadarki en iyi çözüm ...
Crozin

13

Hiçbir şey güzel bir örnek alamaz

İlişkide ekstra özellikler depolamak için 3 katılımcı sınıf arasında bire çok / çoktan bire ilişkilerin temiz bir kodlama örneğini arayanlar için bu siteyi kontrol edin:

3 katılımcı sınıf arasında bire çok / çoktan bire güzel ilişkilendirmeler örneği

Birincil anahtarlarınızı düşünün

Ayrıca birincil anahtarınızı da düşünün. Bunun gibi ilişkiler için genellikle bileşik anahtarlar kullanabilirsiniz. Doktrin bunu doğal olarak desteklemektedir. Referans verdiğiniz varlıkları kimliklere dönüştürebilirsiniz. Kompozit anahtarların belgelerine buradan bakın


10

Ben @ beberlei proxy yöntemlerini kullanma önerisi ile gitmek istiyorum düşünüyorum. Bu işlemi kolaylaştırmak için yapabileceğiniz iki arayüz tanımlamaktır:

interface AlbumInterface {
    public function getAlbumTitle();
    public function getTracklist();
}

interface TrackInterface {
    public function getTrackTitle();
    public function getTrackDuration();
}

Sonra, hem senin Albumve senin Trackederken, bunları uygulayabilir AlbumTrackReferencehala aşağıdaki gibi hem uygulayabilirsiniz:

class Album implements AlbumInterface {
    // implementation
}

class Track implements TrackInterface {
    // implementation
}

/** @Entity whatever */
class AlbumTrackReference implements AlbumInterface, TrackInterface
{
    public function getTrackTitle()
    {
        return $this->track->getTrackTitle();
    }

    public function getTrackDuration()
    {
        return $this->track->getTrackDuration();
    }

    public function getAlbumTitle()
    {
        return $this->album->getAlbumTitle();
    }

    public function getTrackList()
    {
        return $this->album->getTrackList();
    }
}

Bu şekilde, doğrudan a Trackveya a'ya atıfta bulunan mantığınızı kaldırarak Albumve yalnızca a TrackInterfaceveya AlbumInterfacekullanacak şekilde değiştirerek AlbumTrackReference, herhangi bir olası durumda kullanabilirsiniz. İhtiyacınız olan şey, arayüzler arasındaki yöntemleri biraz farklılaştırmaktır.

Bu, DQL'i veya Havuz mantığını farklılaştırmaz, ancak hizmetleriniz yalnızca bir Albumveya bir AlbumTrackReferenceveya bir Trackveya veyaAlbumTrackReference çünkü bir arabirimin arkasındaki her şeyi gizlersiniz :)

Bu yardımcı olur umarım!


7

İlk olarak, onun önerileri konusunda çoğunlukla beberlei ile hemfikirim. Ancak, kendinizi bir tuzağa dönüştürüyor olabilirsiniz. Alan adınız, bir parçanın doğal anahtarı olduğunu düşünüyor gibi görünüyor, bu da karşılaştığınız senaryoların% 99'unda geçerli. Bununla birlikte, Kuklaların Ustası'ndaki Pil , Metallica Koleksiyonu'ndaki sürümden farklı bir sürümse (farklı uzunluk, canlı, akustik, remix, remastered, vb.) .)

Bu durumu nasıl ele almak (veya yoksaymak) istediğinize bağlı olarak, beberlei'nin önerilen rotasına gidebilir veya yalnızca Album :: getTracklist () içindeki önerilen ekstra mantığınızla gidebilirsiniz. Şahsen, ekstra mantığın API'nizi temiz tutmak için haklı olduğunu düşünüyorum, ancak her ikisinin de değeri var.

Kullanım durumumu karşılamak istiyorsanız, Parçaların OneToMany'yi diğer Parçalara, muhtemelen $ similarTracks'a yönlendiren bir içeriğe sahip olmasını sağlayabilirsiniz. Bu durumda, biri Metallica Koleksiyonu ve diğeri Kuklaların Ustası için olmak üzere Pil pisti için iki varlık olacaktır . Daha sonra, her benzer Track varlığı birbirine bir referans içerir. Ayrıca, mevcut AlbumTrackReference sınıfından kurtulup mevcut "sorununuzu" ortadan kaldıracaktır. Sadece karmaşıklığı farklı bir noktaya taşıdığını kabul ediyorum, ancak daha önce yapamadığı bir kullanıcı tabanını işleyebiliyor.


6

"En iyi yol" isteyin ama en iyi yolu yoktur. Birçok yol var ve bunların bazılarını zaten keşfettiniz. İlişkilendirme sınıflarını kullanırken ilişkilendirme yönetimini nasıl yönetmek ve / veya kapsüllemek istediğiniz tamamen size ve somut alanınıza bağlıdır, kimse size "en iyi yolu" gösteremez.

Bunun dışında, Doktrin ve ilişkisel veritabanlarını denklemden çıkararak soru basitleştirilebilir. Sorunuzun özü, düz OOP'ta ilişkilendirme sınıflarıyla nasıl başa çıkılacağı ile ilgili bir soruya dayanmaktadır.


6

Bir ilişkilendirme sınıfı (ek özel alanlar ile) ek açıklama tanımlanmış birleştirme tablosu ve çok-çok ek açıklama tanımlanan bir birleştirme tablosu ile bir çakışma başlamıştı.

Doğrudan çoktan çoğa ilişkisine sahip iki varlıktaki eşleme tanımlarının, 'joinTable' ek açıklamasını kullanarak birleştirme tablosunun otomatik olarak oluşturulmasına neden olduğu ortaya çıktı. Ancak birleştirme tablosu zaten temel varlık sınıfındaki bir ek açıklama ile tanımlanmıştı ve birleştirme tablosunu ek özel alanlarla genişletmek için bu ilişkilendirme varlık sınıfının kendi alan tanımlarını kullanmasını istedim.

Açıklama ve çözüm, yukarıda FMaz008 tarafından tanımlanmaktadır. Benim durumumda, ' Doktrini Ek Açıklama Sorusu ' forumundaki bu yazı sayesinde oldu . Bu yazı, ManyToMany Tek Yönlü ilişkilere ilişkin Doktrin belgelerine dikkat çekiyor . Bir 'ilişkilendirme varlık sınıfı' kullanma yaklaşımına ilişkin nota bakın, böylece doğrudan iki ana varlık sınıfı arasındaki çoktan çoğa ek açıklama eşlemesini, ana varlık sınıflarında bire çok ek açıklama ve iki 'çoktan çoğa' ile değiştirin. -bir 'ilişkisel varlık sınıfında ek açıklamalar. Bu forum mesajında ek alanlı ilişkilendirme modellerinde bir örnek verilmiştir :

public class Person {

  /** @OneToMany(targetEntity="AssignedItems", mappedBy="person") */
  private $assignedItems;

}

public class Items {

    /** @OneToMany(targetEntity="AssignedItems", mappedBy="item") */
    private $assignedPeople;
}

public class AssignedItems {

    /** @ManyToOne(targetEntity="Person")
    * @JoinColumn(name="person_id", referencedColumnName="id")
    */
private $person;

    /** @ManyToOne(targetEntity="Item")
    * @JoinColumn(name="item_id", referencedColumnName="id")
    */
private $item;

}

3

Bu gerçekten faydalı bir örnek. Dokümantasyon doktrininde eksik 2.

Çok teşekkür ederim.

Proxy'ler için işlevler yapılabilir:

class AlbumTrack extends AlbumTrackAbstract {
   ... proxy method.
   function getTitle() {} 
}

class TrackAlbum extends AlbumTrackAbstract {
   ... proxy method.
   function getTitle() {}
}

class AlbumTrackAbstract {
   private $id;
   ....
}

ve

/** @OneToMany(targetEntity="TrackAlbum", mappedBy="album") */
protected $tracklist;

/** @OneToMany(targetEntity="AlbumTrack", mappedBy="track") */
protected $albumsFeaturingThisTrack;

3

Bahsettiğiniz şey meta veriler, veriler hakkındaki verilerdir. Şu anda üzerinde çalıştığım proje için de aynı sorunu yaşadım ve anlamaya çalışmak için biraz zaman harcamak zorunda kaldım. Burada yayınlamak için çok fazla bilgi var, ancak aşağıda yararlı bulabileceğiniz iki bağlantı var. Symfony çerçevesine atıfta bulunurlar, ancak Doktrin ORM'sine dayanırlar.

http://melikedev.com/2010/04/06/symfony-saving-metadata-during-form-save-sort-ids/

http://melikedev.com/2009/12/09/symfony-w-doctrine-saving-many-to-many-mm-relationships/

İyi şanslar ve güzel Metallica referansları!


3

Çözüm Doktrinin belgelerinde. SSS bölümünde bunu görebilirsiniz:

http://docs.doctrine-project.org/en/2.1/reference/faq.html#how-can-i-add-columns-to-a-many-to-many-table

Ve eğitim burada:

http://docs.doctrine-project.org/en/2.1/tutorials/composite-primary-keys.html

Yani artık bir şey yapmıyorsunuz manyToManyama fazladan bir Varlık yaratmalı ve manyToOneiki varlığınıza koymalısınız .

ADD f00bar comment @ için:

basit, sadece böyle bir şey yapmak zorundasınız:

Article  1--N  ArticleTag  N--1  Tag

Böylece bir varlık yaratıyorsunuz ArticleTag

ArticleTag:
  type: entity
  id:
    id:
      type: integer
      generator:
        strategy: AUTO
  manyToOne:
    article:
      targetEntity: Article
      inversedBy: articleTags
  fields: 
    # your extra fields here
  manyToOne:
    tag:
      targetEntity: Tag
      inversedBy: articleTags

Umut ediyorum bu yardım eder



Tam da aradığım şey bu, teşekkürler! Ne yazık ki, üçüncü kullanım durumu için yml örneği yoktur! :(Herkes yml biçimini kullanarak üçüncü kullanım örneğinin bir exabple paylaşabilirsiniz? Gerçekten appriace olur:#
Stphane

davanızın cevabına ekledim;)
Mirza Selimovic

Yanlış. Varlığın id (id) AUTO ile olması gerekmez. Bu yanlış, doğru örneği oluşturmaya çalışıyorum
Gatunox

doğru biçimlendirilmişse almak için yeni bir cevap göndereceğim
Gatunox

3

Tek yönlü. İki yönlü yapmak için inversedBy: (Yabancı Sütun Adı) ekleyin.

# config/yaml/ProductStore.dcm.yml
ProductStore:
  type: entity
  id:
    product:
      associationKey: true
    store:
      associationKey: true
  fields:
    status:
      type: integer(1)
    createdAt:
      type: datetime
    updatedAt:
      type: datetime
  manyToOne:
    product:
      targetEntity: Product
      joinColumn:
        name: product_id
        referencedColumnName: id
    store:
      targetEntity: Store
      joinColumn:
        name: store_id
        referencedColumnName: id

Umut ediyorum bu yardım eder. Görüşürüz.


2

AlbumTrackReference öğesini AlbumTrack olarak değiştirdiğiniz Class Table Inheritance ile istediğinizi başarabilirsiniz:

class AlbumTrack extends Track { /* ... */ }

Ve getTrackList()daha AlbumTracksonra istediğiniz gibi kullanabileceğiniz nesneler içerir :

foreach($album->getTrackList() as $albumTrack)
{
    echo sprintf("\t#%d - %-20s (%s) %s\n", 
        $albumTrack->getPosition(),
        $albumTrack->getTitle(),
        $albumTrack->getDuration()->format('H:i:s'),
        $albumTrack->isPromoted() ? ' - PROMOTED!' : ''
    );
}

Performans açısından acı çekmediğinizden emin olmak için bunu baştan sona incelemeniz gerekecektir.

Şu anki kurulumunuz basit, verimli ve anlambilimin bir kısmı size tam olarak oturmasa bile anlaşılması kolaydır.


0

Tüm albüm parçalarını albüm sınıfının içinde oluştururken, bir kayıt için bir sorgu daha oluşturacaksınız. Bunun nedeni proxy yöntemi. Kodumun başka bir örneği var (konudaki son gönderiye bakın): http://groups.google.com/group/doctrine-user/browse_thread/thread/d1d87c96052e76f7/436b896e83c10868#436b896e83c10868

Bunu çözmek için başka bir yöntem var mı? Tek bir katılım daha iyi bir çözüm değil mi?


1
Bu teorik olarak soruyu cevaplayabilse de , cevabın temel kısımlarını buraya dahil etmek ve referans için bağlantı sağlamak tercih edilir.
Spontifixus

0

İşte Doctrine2 Belgelerinde açıklanan çözüm

<?php
use Doctrine\Common\Collections\ArrayCollection;

/** @Entity */
class Order
{
    /** @Id @Column(type="integer") @GeneratedValue */
    private $id;

    /** @ManyToOne(targetEntity="Customer") */
    private $customer;
    /** @OneToMany(targetEntity="OrderItem", mappedBy="order") */
    private $items;

    /** @Column(type="boolean") */
    private $payed = false;
    /** @Column(type="boolean") */
    private $shipped = false;
    /** @Column(type="datetime") */
    private $created;

    public function __construct(Customer $customer)
    {
        $this->customer = $customer;
        $this->items = new ArrayCollection();
        $this->created = new \DateTime("now");
    }
}

/** @Entity */
class Product
{
    /** @Id @Column(type="integer") @GeneratedValue */
    private $id;

    /** @Column(type="string") */
    private $name;

    /** @Column(type="decimal") */
    private $currentPrice;

    public function getCurrentPrice()
    {
        return $this->currentPrice;
    }
}

/** @Entity */
class OrderItem
{
    /** @Id @ManyToOne(targetEntity="Order") */
    private $order;

    /** @Id @ManyToOne(targetEntity="Product") */
    private $product;

    /** @Column(type="integer") */
    private $amount = 1;

    /** @Column(type="decimal") */
    private $offeredPrice;

    public function __construct(Order $order, Product $product, $amount = 1)
    {
        $this->order = $order;
        $this->product = $product;
        $this->offeredPrice = $product->getCurrentPrice();
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.