clb
clb

Reputation: 723

Symfony/Doctrine inserts null as foreign key in many to one relationship

I have two entities, League and Club, and predictably a League can have many Clubs. Just to test things out I'm trying to insert a club called test into the league with an ID of 1 (which does exist in the database, that's not the problem). If I do the following then it works fine:

$club = new Club();
$club->setName("test");
$league = $this->getDoctrine()->getRepository("AppBundle:League")->find(1);
$club->setLeague($league);
$em->persist($club);
$em->persist($league);
$em->flush();

However, if I alter the fourth line to $league->addClub($club); then it inserts a null value as the league_id in the database.

I have the following code for the Club entity:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Club
 *
 * @ORM\Table(name="club")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ClubRepository")
 */
class Club
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @ORM\ManyToOne(targetEntity="League", inversedBy="clubs")
     * @ORM\JoinColumn(name="league_id", referencedColumnName="id")
     */
    private $league;


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

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Club
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * Set league
     *
     * @param \AppBundle\Entity\League $league
     *
     * @return Club
     */
    public function setLeague(\AppBundle\Entity\League $league = null)
    {
        $this->league = $league;

        return $this;
    }

    /**
     * Get league
     *
     * @return \AppBundle\Entity\League
     */
    public function getLeague()
    {
        return $this->league;
    }
}

and the following for the League entity:

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * League
 *
 * @ORM\Table(name="league")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\LeagueRepository")
 */
class League
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity="Club", mappedBy="league")
     */
    private $clubs;


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

    /**
     * Set name
     *
     * @param string $name
     *
     * @return League
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }
    /**
     * Constructor
     */
    public function __construct()
    {
        $this->clubs = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add club
     *
     * @param \AppBundle\Entity\Club $club
     *
     * @return League
     */
    public function addClub(\AppBundle\Entity\Club $club)
    {
        $this->clubs[] = $club;

        return $this;
    }

    /**
     * Remove club
     *
     * @param \AppBundle\Entity\Club $club
     */
    public function removeClub(\AppBundle\Entity\Club $club)
    {
        $this->clubs->removeElement($club);
    }

    /**
     * Get clubs
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getClubs()
    {
        return $this->clubs;
    }
}

I've checked that the database schema is up to data with doctrine:schema:update, and I've tried seemingly every combination of persisting and flushing... persisting the club before the league, persisting the league before the club, persisting just the league, persisting just the club, persisting the league then flushing then persisting the club then flushing again... Nothing has worked.

Upvotes: 2

Views: 2587

Answers (2)

JimL
JimL

Reputation: 2541

Doctrine will only check the owning side of an association for changes. http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html

You can cascade changes to the owning side like this

// AppBundle\Entity\League.php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * League
 *
 * @ORM\Table(name="league")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\LeagueRepository")
 */
class League
{

    // ...

    /**
     * Add club
     *
     * @param \AppBundle\Entity\Club $club
     *
     * @return League
     */
    public function addClub(\AppBundle\Entity\Club $club)
    {
        $this->clubs[] = $club;
        $club->setLeague($this);

        return $this;
    }

    // ...
}

Upvotes: 0

lolmx
lolmx

Reputation: 521

The problem comes from your addClub()method. When you add a club in the league, you have to tell the club in which league it's being added.

Your method should look like this

public function addClub(Club $club)
{
    $this-cubs[] = $club;
    $club->setLeague($this); // <-- there, tell the club in which league it is

    return $this;
}

Upvotes: 1

Related Questions