Ik heb 3 tabellen:

* Travel
* Youtube
* rel_travel_youtube.

1 reis kan meerdere youtube filmps hebben en 1 film kan bij meerdere reizen horen.

Via de cli heb ik de 2 entiteiten gekregen:
* Travel
* Youtube

Er is dus geen entiteit van de koppeltabel aanwezig.
Beide kolommen binnen de koppeltabel zijn gedfineerd als primary key(s).

Ik loop door een feed heen en per element insert ik de data.
Wanneer een video key al bestaat, krijg ik netjes de melding terug dat de waarde al voorkomt. ( unique ), maar dan wil ik alsnog een record in de koppeltabel inschieten.. Ik krijg het maar niet voor elkaar.

Wat extra info:

Entiteit: Travel

<?php
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="Youtube", inversedBy="travel", cascade={"persist"})
* @ORM\JoinTable(name="rel_travel_youtube",
* joinColumns={
* @ORM\JoinColumn(name="travel_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="youtube_id", referencedColumnName="id")
* }
* )
*/
private $youtube;

/**
* Add youtube
*
* @param \Application\Entity\Youtube $youtube
* @return Travel
*/
public function addYoutube(\Application\Entity\Youtube $youtube)
{
$this->youtube[] = $youtube;

return $this;
}
?>

Entiteit: Youtube

<?php
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="Travel", mappedBy="youtube")
*/
private $travel;
?>

Voor de mensen met kennis van Doctrine2 is mijn vraag hopelijk met deze informatie te beantwoorden.

Alvast bedankt!

Als ik het allemaal zo doorlees dan denk ik dat je makkelijker met een bidirectional many-to-many af bent:
<?php
class Travel
{
// ...

/**
* @ORM/ManyToMany(targetEntity="Movie", inversedBy="travels")
* @ORM/JoinTable(name="travels_movies")
*/
private $movies;

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

// ...
}

/** @Entity */
class Movie
{
// ...
/**
* @ORM/ManyToMany(targetEntity="Travel", mappedBy="movies")
*/
private $travels;

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

// ...
}
?>

Als je deze entities genereert dan krijg je in beiden classen een addMovie() / addTravel() method. Waneer een film al in de tabel aanwezig is doe je dan vervolgens gewoon in de enitity van DIE film de addTravel() method aanroepen. en niet vergeten de persist en flush aan te roepen natuurlijk.
Oke je uitleg is duidelijk. Heb ik nog een nieuwe vraag:
<?php
case 'youtube_video_key':
$oObj = $oObjectManager->getRepository( '\Application\Entity\Youtube' )->findOneBy( array( 'video' => $o->nodeValue ) );
if( null !== $oObj )
{
$oObj->addTravel( $oTravel );
}
else
{
$oYoutube->setVideo( $o->nodeValue );
$oObjectManager->persist( $oYoutube );
$oObjectManager->flush();

$oTravel->addYoutube( $oYoutube );
}
break;
?>

De koppeltabel wordt netjes gevuld, maar in tabel ´youtube´ worden de records dubbel ingeschoten.. Wanneer ik de kolom ´video´ uniek maak, krijg ik het helemaal niet meer voor elkaar.
Ik zie $oObj die een Youtube entity in zich heeft en ik zie een $oYoutube. Waar komt die laatste vandaan?
Dat is een instantie van de entiteit:

$oYoutube = new Youtube();
Ok je maakt dus een nieuwe entity aan zet de unieke youtube code in die entity en je slaat hem op in de database. Vervolgens Koppel je deze aan de $oTravel entity. Kan het zijn dat je deze dan ook nog eens opslaat met
<?php
$oObjectManager->persist( $oTravel );
$oObjectManager->flush();
?>
???

Volgens mij is dit beter (hoop ik)
<?php
$oYoutube = $oObjectManager->getRepository( '\Application\Entity\Youtube' )->findOneBy( array( 'video' => $o->nodeValue ) );

if( $oYoutube == null )
{
$oYoutube = new \Application\Entity\Youtube();
}

$oYoutube->setVideo( $o->nodeValue );
$oObjectManager->persist( $oYoutube );


$oTravel->addYoutube( $oYoutube );

$oObjectManager->persist( $oTravel );

$oObjectManager->flush(); // je hoeft altijd maar één keer flush() aan te roepen

?>
Over onlogica gesproken:
<?php
findOneBy( array( 'video' => $o->nodeValue );
?>


Sorry te snel.
Ik heb m nog iets aangepast. dus nog een keer proberen aub?
Hmm, de logica van het script is volgens mij een beetje kwijt. Of dat komt door vreemde variabele benamingen weet ik niet, maar het helpt er in elk geval wel aan mee :)

Wat jij nu doet:
- Selecteer Youtube waar video = $o->nodeValue
- Vervolgens set je video in op $o->nodeValue (dat is niet nodig, want daar heb je hem op geselecteerd)
- Je persist dan Youtube (die nog steeds hetzelfde is)
- Dan ga je met Travel aan de slag

Behalve dat het script dus eigenlijk niks doet is de persist van Youtube ook verkeerd. Persist betekend namelijk een CREATE query. Je selecteert dus eerst een Youtube object, doet daar vervolgens niks mee en zegt dan tegen Doctrine dat hij dat Youtube object in de database moet aanmaken. Dan krijg je dus 2 dezelfde rijen in je tabel. Sterker nog, als je hem nog een keer runt krijg je er 3 :)

Als je iets update (wat je hier dus niet doet) hoef je alleen maar ->flush() aan te roepen. Doctrine ontdekt zelf welke geselecteerde entities aangepast zijn en welke dus een UPDATE query nodig hebben.

Volgens mij is dit hele probleem dus slechts een verkeerd geplaatste accolade: De accolade van Regel 7 moet naar regel 11:

<?php
$oYoutube = $oObjectManager->getRepository( '\Application\Entity\Youtube' )->findOneBy( array( 'video' => $o->nodeValue ) );

if( $oYoutube == null )
{
$oYoutube = new \Application\Entity\Youtube();

$oYoutube->setVideo( $o->nodeValue );
$oObjectManager->persist( $oYoutube );
}

$oTravel->addYoutube( $oYoutube );

$oObjectManager->persist( $oTravel );

$oObjectManager->flush(); // je hoeft altijd maar één keer flush() aan te roepen

?>
Komt nu met de melding:

An exception occurred while executing 'INSERT INTO rel_travel_youtube (travel_id, youtube_id) VALUES (?, ?)' with params [5839, 47616]:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '5839-47616' for key 'PRIMARY'

code
<?php
public function indexAction()
{
$oObjectManager = $this->getServiceLocator()->get( 'Doctrine\ORM\EntityManager' );

$oTravel = new Travel();

$oXmlReader = new \XMLReader();

foreach( $this->aXmlFiles as $sFilename )
{
$oXmlReader->open( $sFilename );

while( $oXmlReader->read() )
{
if( $oXmlReader->nodeType == \XMLReader::ELEMENT )
{
if( $oXmlReader->name == self::GROUP_ELEMENT_NAME )
{
while( $oXmlReader->read() )
{
if( $oXmlReader->nodeType === \XMLReader::ELEMENT )
{
$o = $oXmlReader->expand();

if( !empty( $o->nodeValue ) )
{
switch( strtolower( $o->nodeName ) )
{
case 'accommodation_name':
break;

case 'city_of_destination':
break;

case 'country_of_destination':
break;

case 'description':
$oTravel->setDescription( $o->nodeValue );
break;

case 'img_medium':
$oTravel->setImgMedium( $o->nodeValue );
break;

case 'link':
$oTravel->setLink( $o->nodeValue );
break;

case 'min_nr_people':
$oTravel->setNrOfGuests( $o->nodeValue );
break;

case 'minimum_price':
$oTravel->setPrice( $o->nodeValue );
break;

case 'region_of_destination':
break;

case 'title':
$oSeoUrl = $this->getServiceLocator()->get( 'SeoUrl\Slug' );

$oTravel->setName( $o->nodeValue );
$oTravel->setSlug( $oSeoUrl->create( $o->nodeValue ) );
break;

case 'youtube_video_key':
$oYoutube = $oObjectManager->getRepository( '\Application\Entity\Youtube' )->findOneBy( array( 'video' => $o->nodeValue ) );
if( $oYoutube == null )
{
$oYoutube = new Youtube();
$oYoutube->setVideo( $o->nodeValue );
$oObjectManager->persist( $oYoutube );
}
$oTravel->addYoutube( $oYoutube );
break;
}
}
}
if( $oXmlReader->nodeType == \XMLReader::END_ELEMENT && $oXmlReader->name == self::GROUP_ELEMENT_NAME )
{
$oTravel->setStatus( self::ACTIVE );

$oObjectManager->persist( $oTravel );
$oObjectManager->flush();
}
}
}
}
}
}
return new ViewModel();
}
?>

Toevoeging op 18/05/2014 22:03:13:

<?php
$oObjectManager->persist( $oTravel );
$oObjectManager->flush();
$oObjectManager->clear();
?>

Ik heb clear() nog aan het einde toegevoegd en dan krijg ik de melding:
An exception occurred while executing 'INSERT INTO youtube (video) VALUES (?)' with params ["1XHA0t0zHFo"]:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1XHA0t0zHFo' for key 'video'

Toevoeging op 18/05/2014 22:05:33:

rel_travel_youtube

Gedeelde primary key & de volgende query nog uitgevoerd:

ALTER TABLE `rel_travel_youtube` DROP FOREIGN KEY `rel_travel_youtube_ibfk_1`; ALTER TABLE `rel_travel_youtube` ADD CONSTRAINT `rel_travel_youtube_ibfk_1` FOREIGN KEY (`travel_id`) REFERENCES `vacation`.`travel`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE `rel_travel_youtube` DROP FOREIGN KEY `rel_travel_youtube_ibfk_2`; ALTER TABLE `rel_travel_youtube` ADD CONSTRAINT `rel_travel_youtube_ibfk_2` FOREIGN KEY (`youtube_id`) REFERENCES `vacation`.`youtube`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
De foutmelding is wel duidelijk toch? Duplicate entry '5839-47616' for key 'PRIMARY'

Reageren