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!

Mee eens.. Maar ik schiet het record ook niet in om het moment dat ik resultaat krijg op mn findOneBy select.
Ik wil een nieuw record in rel_travel_youtube, dat wel.

Omdat ze een relatie met elkaar hebben, zal de insert waarschijnlijk wel dubbel uitgevoerd worden met als resultaat een duplicate entry..

Het gaat nu wel om deze trouwens: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1XHA0t0zHFo' for key 'video'
Je kunt geen extra records in de koppeltabel invoegen. En als je het wel doet/kunt dan is het geen koppeltabel meer. Je zou er dan een entity van moeten maken.

Waarom denk je de hele tijd aan de koppeltabel terwijl je met doctrine hier totaal geen omkijken naar hebt?

Toevoeging op 18/05/2014 23:18:03:

Ga je nu zelf die koppeltabel handmatig zitten veranderen?
travel
* id
* name

rel_travel_youtube
* travel_id
* youtube_id

youtube
* id
* video

De relaties zoals ze zijn staan hierboven vermeld.
Ik heb de entiteiten laten genereren dmv: orm:convert-mapping. Hierdoor het ik de beschikking over de entiteiten: Youtube & Travel.

Als ik de youtube entiteit vul, en deze toevoeg aan Travel dmv: $oTravel->addYoutube( $oYoutube ), wordt deze geplaatst in de youtube tabel en is er een record bijgekomen in de rel_travel_youtube tabel.

So far so good. Hopelijk voor jullie ook nog helder.

de kolom: video, is uniek. En bij een een volgende keer dat ik een record wil inschieten met dezelfde video key, krijg ik een error dat het record al bestaat, wat ook logisch is.

Maar ik wil het ID van dat record gebruiken, om in rel_travel_youtube een nieuw record te maken.


rel_travel_youtube
travel_id	youtube_id
1			1
2			1


Denk ik verkeerd o.i.d.? Ik hoor het graag!
Nou leg je het heel helder uit allemaal maar ik mis nog steeds de reden WAAROM je een record wilt maken in de koppeltabel (rel_travel_youtube).

Volgens mij is het antwoord dat je één film aan meerdere reizen kunt koppelen.

Je hoeft met doctrine nooit en te nimmer eigenhandig aan een koppeltabel te knoeien.
Wat jij doet zoals je het verteld: een record proberen toe te voegen aan de tabel youtube en afwachten of er een foutmelding komt. Draai die gedachte nou eens om en doe dan dit:
... ->findOneBy( array( 'video' => $youtubeCode )
Er kunnen nu twee dingen gebeuren: Je krijgt een entity terug met alle velden ingevuld van het gevonden record OF je krijgt een NULL terug als de youtube-code dus niet in de database voorkomt.

Vervolgens is het eigenlijk heel simpel:
Indien NULL: Creëer een nieuwe youtube entity, roep alle setters aan om de properties de juiste waarden te geven en roep addTravel aan om aan de youtube entity een travel te hangen. (welke je al in je database zou moeten hebben staan).
Indien je een entity terugkrijgt:
Hoef je enkel de addTravel aan te roepen. Immers het record bestaat al in de database maar je wilt een extra record in de koppeltabel.

Dat klinkt logisch en dat is ook precies wat ik doe. Maar toch:

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'

Wordt er door de addYoutube() functie niet geprobeerd om het record in in de youtube tabel in te schieten?
Ik kan niks anders bedenken

Toevoeging op 19/05/2014 19:04:49:

Als ik aangeef dat de kolom 'video' niet uniek is, krijg ik allemaal record met dezelfde waarde in de kolom, maar in de koppeltabel gaat het wel automatisch goed.
Erik Rijk op 19/05/2014 19:01:08

Als ik aangeef dat de kolom 'video' niet uniek is, krijg ik allemaal record met dezelfde waarde in de kolom, maar in de koppeltabel gaat het wel automatisch goed.


Dan gaat er nog iets mis met het persisten naar je database. Je probeert een bestaande entity nogmaals te INSERTEN
Dit heb ik nu. Klein deel in commentaar.. Ik krijg het niet voor elkaar :-/ Alle mogelijke situaties hebben zich voorgedaan tijdens mn geknutsel, behalve het geen wat ik graag wil :)

Op basis van het geheel.. Wat raad je aan?

<?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':
if( null === ( $oCity = $oObjectManager->getRepository( '\Application\Entity\City' )->findOneBy( array( 'name' => $o->nodeValue ) ) ) )
{
$oCity = new City();
$oCity->setName( $o->nodeValue );
$oObjectManager->persist( $oCity );
}
$oTravel->setCity( $oCity );
break;

case 'country_of_destination':
if( null === ( $oCountry = $oObjectManager->getRepository( '\Application\Entity\Country' )->findOneBy( array( 'abbreviation' => $o->nodeValue ) ) ) )
{
$oCountry = new Country();
$oCountry->setAbbreviation( $o->nodeValue );
$oCountry->setName( $o->nodeValue );
$oObjectManager->persist( $oCountry );
}
$oTravel->setCountry( $oCountry );
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':
if( null === ( $oRegion = $oObjectManager->getRepository( '\Application\Entity\Region' )->findOneBy( array( 'name' => $o->nodeValue ) ) ) )
{
$oRegion = new Region();
$oRegion->setName( $o->nodeValue );
$oObjectManager->persist( $oRegion );
}
$oTravel->setRegion( $oRegion );
break;

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

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

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

$oObjectManager->persist( $oTravel );
$oObjectManager->flush();
$oObjectManager->clear();
}
}
}
}
}
}
return new ViewModel();
}
?>
Ik heb de boel eens nagebouwd en inderdaad lijkt het niet te werken icm met video als primary key

de foutmelding die hij bij mij geeft slaat op de koppeltabel

Toevoeging op 19/05/2014 22:07:24:

EDIT: Toch gelukt.

Toevoeging op 19/05/2014 22:10:48:

entity movie:
<?php

namespace FrankBeen\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
* Movie
*
* @ORM\Table(name="movies")
* @ORM\Entity
*/
class Movie
{
/**
* @var string
* @ORM\Id
* @ORM\Column(name="video", type="string", length=64, nullable=false)
*/
private $video;

/**
* @var string
*
* @ORM\Column(name="title", type="string", length=64, nullable=false)
*/
private $title;

/**
* @ORM\ManyToMany(targetEntity="Travel", mappedBy="movies")
*/
private $travels;

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

/**
* Set video
*
* @param string $video
* @return Movie
*/
public function setVideo($video)
{
$this->video = $video;

return $this;
}

/**
* Get video
*
* @return string
*/
public function getVideo()
{
return $this->video;
}

/**
* Set title
*
* @param string $title
* @return Movie
*/
public function setTitle($title)
{
$this->title = $title;

return $this;
}

/**
* Get title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}

/**
* Add travels
*
* @param \FrankBeen\MainBundle\Entity\Travel $travels
* @return Movie
*/
public function addTravel(\FrankBeen\MainBundle\Entity\Travel $travels)
{
$this->travels[] = $travels;

return $this;
}

/**
* Remove travels
*
* @param \FrankBeen\MainBundle\Entity\Travel $travels
*/
public function removeTravel(\FrankBeen\MainBundle\Entity\Travel $travels)
{
$this->travels->removeElement($travels);
}

/**
* Get travels
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getTravels()
{
return $this->travels;
}
}
?>
entity travel:
<?php

namespace FrankBeen\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
* Travel
*
* @ORM\Table(name="travels")
* @ORM\Entity
*/
class Travel
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;

/**
* @var string
*
* @ORM\Column(name="title", type="string", length=64, nullable=false)
*/
private $title;

/**
* @ORM\ManyToMany(targetEntity="Movie", inversedBy="travels")
* @ORM\JoinTable(name="travels_movies",
* joinColumns={@ORM\JoinColumn(name="travel_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="video_id", referencedColumnName="video")}
* )
*/
private $movies;

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

/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}

/**
* Set title
*
* @param string $title
* @return Travel
*/
public function setTitle($title)
{
$this->title = $title;

return $this;
}

/**
* Get title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}

/**
* Add movies
*
* @param \FrankBeen\MainBundle\Entity\Movie $movies
* @return Travel
*/
public function addMovie(\FrankBeen\MainBundle\Entity\Movie $movies)
{
$this->movies[] = $movies;

return $this;
}

/**
* Remove movies
*
* @param \FrankBeen\MainBundle\Entity\Movie $movies
*/
public function removeMovie(\FrankBeen\MainBundle\Entity\Movie $movies)
{
$this->movies->removeElement($movies);
}

/**
* Get movies
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getMovies()
{
return $this->movies;
}
}
?>
Controller:
<?php

namespace FrankBeen\MainBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
public function indexAction($name)
{
$video = 'v=g_r4a-DXA7c';

$em = $this->getDoctrine()->getManager();

$movie = $em->getRepository('MainBundle:Movie')->findOneBy(array('video' => $video));
if($movie == NULL)
{
$movie = new \FrankBeen\MainBundle\Entity\Movie();
$movie->setVideo('v=g_r4a-DXA7c');
$movie->setTitle('PHP contactformulier en PHPMailer');
$em->persist($movie);
}

$travel = new \FrankBeen\MainBundle\Entity\Travel();
$travel->setTitle('travel A');
$travel->addMovie($movie);
$em->persist($travel);

$travel2 = new \FrankBeen\MainBundle\Entity\Travel(); // <-- MOEST ECHT EEN NEW Travel() MAKEN!!!!
$travel2->setTitle('travel B');
$travel2->addMovie($movie);
$em->persist($travel2);
$em->flush();

return $this->render('MainBundle:Default:index.html.twig', array('name' => $name));
}
}
?>

Reageren