This example shows us how we create one-to-many composition relationship with Doctrine and Symfony.


Notes



Design




Mapping


Continent


declare(strict_types=1);

namespace AppBundle\Entity;

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

/**
* @ORM\Entity
* @ORM\Table(name="continent", uniqueConstraints={@ORM\UniqueConstraint(columns={"name"})})
*/
class Continent
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

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

/**
* @ORM\OneToMany(targetEntity="Country", mappedBy="continent", cascade={"persist", "remove"})
*/
private $countries;

public function __construct()
{
$this->countries = new ArrayCollection();
}

public function getId(): int
{
return $this->id;
}

public function setName(string $name): self
{
$this->name = $name;

return $this;
}

public function getName(): string
{
return $this->name;
}

public function addCountry(Country $country): self
{
$this->countries[] = $country;

return $this;
}

public function removeCountry(Country $country): bool
{
return $this->countries->removeElement($country);
}

public function getCountries(): Collection
{
return $this->countries;
}
}

Country


declare(strict_types=1);

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity
* @ORM\Table(name="country", uniqueConstraints={@ORM\UniqueConstraint(columns={"name"})})
*/
class Country
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

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

/**
* @ORM\ManyToOne(targetEntity="Continent", inversedBy="countries", cascade={"persist"})
* @ORM\JoinColumn(name="continent_id", referencedColumnName="id", nullable=false)
*/
private $continent;

public function getId(): int
{
return $this->id;
}

public function setName(string $name): self
{
$this->name = $name;

return $this;
}

public function getName(): string
{
return $this->name;
}

public function setContinent(Continent $continent): self
{
$this->continent = $continent;

return $this;
}

public function getContinent(): Continent
{
return $this->continent;
}
}

Database


CREATE TABLE `continent` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(13) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UNIQ_6CC70C7C5E237E06` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `country` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`continent_id` int(11) NOT NULL,
`name` varchar(13) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UNIQ_5373C9665E237E06` (`name`),
KEY `IDX_5373C966921F4C77` (`continent_id`),
CONSTRAINT `FK_5373C966921F4C77` FOREIGN KEY (`continent_id`) REFERENCES `continent` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Tests


Create a new Continent.


$continent = new Continent();
$continent->setName('Africa');

$this->entityManager->persist($continent);
$this->entityManager->flush();

Create a new Continent and Country at same time.


$country = new Country();
$country->setName('Gana');

$continent = new Continent();
$continent->setName('Africa');

$country->setContinent($continent);
$continent->addCountry($country);

// You can use both of them at same time but using one over another is more logical as cascade={"persist"} will handle it for us.
$this->entityManager->persist($continent);
$this->entityManager->persist($country);
//

$this->entityManager->flush();

Creating a new Country.


/** @var Continent $continent */
$continent = $this->entityManager->getRepository(Continent::class)->findOneById(1);

$country = new Country();
$country->setName('Gana');
$country->setContinent($continent);

// You can use both of them at same time but using one over another is more logical as cascade={"persist"} will handle it for us.
$continent->addCountry($country);
$this->entityManager->persist($country);
//

$this->entityManager->flush();