Bonjour,

Le pensais avoir résolu mon problème, mais ce n'est pas le cas.

J'ai un formulaire lié à une entité annonce contenant des formulaires embarqués : un formulaire classique lié à un véhicule et un formulaire qui alimente une collection de photos. Lors de l'enregistrement d'une annonce ne contenant qu'une seule photo, tout se passe bien : l'annonce, le véhicule et la photo sont bien enregistrés dans leurs tables respectives.

Cependant, dès que j'essaie de lier plusieurs photos à l'annonce, j'obtiens l'erreur de violation de contrainte d'intégrité suivante :

"An exception occurred while executing 'INSERT INTO photo (name, id) VALUES (?, ?)' with params ["8435c4ae91b0277c15b669c0a50ced0b.jpeg", null]:

SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (roadtrip.photo, CONSTRAINT FK_14B78418BF396750 FOREIGN KEY (id) REFERENCES advert (id))"

Je ne parviens pas à détecter la source du problème. Pourriez-vous m'aider? Voici les sources qui pourraient aider :

Dans mon entité "Advert" :

...
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $id;
...
    /**
     * @ORM\OneToOne(targetEntity="App\Entity\Vehicle", inversedBy="advert", cascade={"persist", "remove"})
     * @ORM\JoinColumn(nullable=false)
     * 
     * @Assert\Type(type="App\Entity\Vehicle")
     * @Assert\Valid()
     */
    private $vehicle;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Photo", mappedBy="advert", cascade={"persist"}, orphanRemoval=true)
     */
    private $photos;

    public function __construct() 
    {
        $this->photos = new ArrayCollection();
    }
...
    public function getVehicle(): ?Vehicle
    {
        return $this->vehicle;
    }

    public function setVehicle(Vehicle $vehicle): self
    {
        $this->vehicle = $vehicle;
        $this->vehicle->setAdvert($this);

        return $this;
    }

    /**
     * @return Collection|Photo[]
     */
    public function getPhotos(): ArrayCollection
    {
        return $this->photos;
    }

    public function setPhotos(ArrayCollection $photos)
    {
        $this->photos = $photos;
    }

    public function addPhoto(Photo $photo): self
    {
        if (!$this->photos->contains($photo)) {
            $this->photos[] = $photo;
            $photo->setAdvert($this);
        }

        return $this;
    }
... 

Dans mon entité "Vehicle" :

...
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;
...
    /**
     * @ORM\OneToOne(targetEntity="App\Entity\Advert", mappedBy="vehicle", cascade={"persist", "remove"})
     */
    private $advert;
...
    public function getAdvert(): ?Advert
    {
        return $this->advert;
    }

    public function setAdvert(Advert $advert): self
    {
        $this->advert = $advert;

        // set the owning side of the relation if necessary
        if ($this !== $advert->getVehicle()) {
            $advert->setVehicle($this);
        }

        return $this;
    }
...

Dans mon entité "Photo" :

...
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $id;
...
    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Advert", inversedBy="photos")
     * @ORM\JoinColumn(name="id", referencedColumnName="id")
     */
    private $advert;
...
    public function getAvert(): ?Advert
    {
        return $this->advert;
    }

    public function setAdvert(Advert $advert): self
    {
        $this->advert = $advert;

        return $this;
    }
...

Et enfin, dans mon controller :

...
    public function advertForm(Advert $advert = null, Request $request, ObjectManager $manager){

        if (!$advert) {
            $advert = new Advert();
            $vehicle = new Vehicle();
            $advert->setVehicle($vehicle);
            $vehicle->setAdvert($advert);
        }

        $form = $this->createForm(AdvertType::class, $advert);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {

            //If it's a new advert, date assignment and expiration date assignement
            $now = new \DateTime('now');

            $advert->setCreatedAt($now);
            $advert->SetExpiresAt($now->add(new DateInterval($this->getParameter('advert_active_duration'))));

            $photos = $advert->getPhotos();

            foreach ($photos as $photo) {

                $advert->addPhoto($photo);

                // If no file is set, do nothing
                if (null !== $photo->getFile())
                {               

                    $photo->setName(md5(uniqid()) . '.' . $photo->getFile()->guessExtension());

                    try 
                    {
                        $photo->getFile()->move($this->getParameter('photos_directory'), $photo->getName());
                    } 
                    catch (FileException $e) 
                    {
                        // ... handle exception if something happens during file upload
                    }

                }

            }           

            $manager->persist($advert);
            $manager->flush();

        }

        return $this->render('road_trip/createAdvert.html.twig', ['formAdvert' => $form->createView(), 'editMode' => $advert->getId() !== null]);        
    }
...

Edit 1 :

J'ai remarqué que la colonne "advert_id" n'était pas créée dans ma table "photo". J'ai donc modifié l'attribut "advert" comme suit dans ma classe "Photo" :

"An exception occurred while executing 'INSERT INTO photo (name, advert_id) VALUES (?, ?)' with params ["025e2ba9ec1f70a88c18546ef202fd68.jpeg", null]:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'advert_id' cannot be null"

Edit 2 :

En supprimant "* @ORM\JoinColumn(nullable=false)" et en permettant le null dans le champ correspondant dans ma table, ça fonctionne correctement. Cependant, je ne trouve pas ça logique ni propore, du fait qu'une photo doit impérativement être liée à une annonce. Quelqu'un a une idée?

Merci d'avance pour votre aide!

1 réponse


dubitoph
Auteur
Réponse acceptée

Problème résolu