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
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.
Bir ilişki veri bir kere, artık bir ilişkisi var !
Django bir sayfada birden fazla form i...
'işlemek için en kolay yolu ne ve...
Nasıl numpy bir dizi için ekstra bir s...
Bir nesneyi klonlamak için en etkili y...
Hareket Gıt ile yeni bir şube için en ...