SORU
22 AĞUSTOS 2010, Pazar


Doctrine2: en İyi işlemek için çok çok ekstra bir sütun başvurusu tabloda yolu

En iyi, en temiz ve Doctrine2 içinde çok-çok ilişkileri ile çalışmak için en basit yolu merak ediyorum.

Hadi birkaç parça ile Master of Puppets by Metallica gibi bir albüm var varsayalım. Ama lütfen bir parça daha, bir albüm olarak görünür ihtimalini de not Battery by Metallica gibi - üç albüm özelliğine de sahip bu parça.

Çok ihtiyacım olan şey albüm ve parçalar arasında çok-çok ilişki, bazı ek sütunlar (belirtilen albümde parçanın konumu gibi) ile üçüncü tablo kullanıyor. Aslında işlevsellik Doktrini belgelerine de anlaşılacağı gibi, elde etmek için bir çok çift bir 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 albüm ve parça onlarla ilişkili listesini görüntüle.

$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ı bekliyorum, yani: uygun sırayla parça ve terfi olanlar terfi olarak işaretlenmiş albümler 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) 

Yanlış olan ne?

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

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

Album::getTracklist() AlbumTrackReference bir dizi Track nesneler yerine nesneleri döndürür. Eğer, Album Track getTitle() yöntem olurdu proxy yöntemleri oluşturamıyorum neden? Album::getTracklist() yöntem içinde bazı ekstra işlem ama bunu yapmak için en basit yolu nedir? yapabilirim Öyle bir şey yazmak zorunda mıyı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

EDİT

@proxy yöntemleri kullanmak için önerilen beberlei:

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

Bu iyi bir fikir olabilir ama ben kullanarak bu "referans nesnesi" her iki taraftan: $album->getTracklist()[12]->getTitle() $track->getAlbums()[1]->getTitle() getTitle() yöntem dönmeyin farklı veri tabanlı içerik çağırma.

Gibi bir şey yapmak istiyorum:

 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 çok temiz bir yol değil.

CEVAP
2 Kasım 2011, ÇARŞAMBA


Doktrin kullanıcı posta listesine benzer bir soru açtı ve çok basit bir cevabı var;

bir varlık olarak, daha çok ilişki düşünün kendisi, ve sonra 3 nesneleri, aralarında bir-çok ve çok-bir ilişki ile bağlantılı olduğunun farkında mısın.

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

Bir ilişki veri bir kere, artık bir ilişkisi var !

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • pilslajt

    pilslajt

    20 HAZİRAN 2008
  • RobertDuskin

    RobertDuskin

    12 HAZİRAN 2008
  • Strata1000

    Strata1000

    28 EYLÜL 2009