Symfony doesnt auto increment id - php

I have a database called cardb which is populated by a SQL file which made some cars. They have ID's starting from 1 up to 30. When I try to create new Car it works the first time and creates a car with id 0 then when it tries to do it again it again tries to make an entry with 0.
Here is the error
An exception occurred while executing 'INSERT INTO cars (Make, Model, TravelledDistance) VALUES (?, ?, ?)' with params ["fock", "fock", 320]:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '0' for key 'PRIMARY'
Here is my entity
/**
* Cars
*
* #ORM\Table(name="cars")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CarsRepository")
*/
class Cars
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="Make", type="string", length=255)
*/
private $make;
/**
* #var string
*
* #ORM\Column(name="Model", type="string", length=255)
*/
private $model;
/**
* #var int
*
* #ORM\Column(name="TravelledDistance", type="bigint")
*/
private $travelledDistance;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Parts", inversedBy="cars")
* #ORM\JoinTable(
* name="PartCars",
* joinColumns={
* #ORM\JoinColumn(name="Part_Id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="Car_Id", referencedColumnName="id")
* })
*/
private $parts;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set make
*
* #param string $make
*
* #return Cars
*/
public function setMake($make)
{
$this->make = $make;
return $this;
}
/**
* Get make
*
* #return string
*/
public function getMake()
{
return $this->make;
}
/**
* Set model
*
* #param string $model
*
* #return Cars
*/
public function setModel($model)
{
$this->model = $model;
return $this;
}
/**
* Get model
*
* #return string
*/
public function getModel()
{
return $this->model;
}
/**
* Set travelledDistance
*
* #param integer $travelledDistance
*
* #return Cars
*/
public function setTravelledDistance($travelledDistance)
{
$this->travelledDistance = $travelledDistance;
return $this;
}
/**
* Get travelledDistance
*
* #return int
*/
public function getTravelledDistance()
{
return $this->travelledDistance;
}
/**
* #return mixed
*/
public function getParts()
{
return $this->parts;
}
}
It is auto generated Entity which has auto increment annotation.
What could be the problem?

The annotation
* #ORM\GeneratedValue(strategy="AUTO")
won't make PHP create a unique ID. You can see from the insert statement that PHP doesn't provide an ID value at all.
That annotation tells the ORM what kind of column it is, but it depends on the database to generate the value. You can check the documentation for more details.
Based on the way your code looks, it appears you used the console to generate the entity, but I assume the fact that the database isn't doing the id properly means that you created the cars table by hand rather than using doctrine:schema:update, which is fine if that's the way you need/want to do it, but you'll have to alter your table to make the id column an autoincrement.

Related

Doctrine 3 does not create the foreign key - PDOException: "Column 'tour_id' cannot be null"

I'm trying to insert a new record in the database.
I have two tables bootstrap_tour and bootstrap_tour_step.
id of boostrap_tour table is the foreign key tour_id in the bootstrap_tour_step table.
The corresponding entities look as follows:
BootstrapTour.php
/**
* #var int
*
* #ORM\Column(name="id", type="integer", options={"unsigned"=true})
* #ORM\Id
*
* #JMS\Groups({"auth_read_postbootstraptours"})
* #JMS\Type("integer")
* #JMS\Accessor(getter="getId")
*/
protected $id;
/**
* #var ArrayCollection[BootstrapTourStep]
*
* #ORM\OneToMany(targetEntity="BootstrapTourStep", mappedBy="bootstrapTour", cascade={"persist"})
*
* #JMS\Groups({"auth_read_postbootstraptours"})
*/
private $bootstrapTourSteps;
/**
* Object instantiation.
*/
public function __construct()
{
parent::__construct();
$this->bootstrapTourSteps = new ArrayCollection();
}
/**
* Sets a collection of BootstrapTourStep objects.
*
* #param ArrayCollection|null $bootstrapTourSteps
*
* #return BootstrapTour
*/
public function setBootstrapTourSteps(?ArrayCollection $bootstrapTourSteps): BootstrapTour
{
$this->bootstrapTourSteps = $bootstrapTourSteps;
return $this;
}
/**
* Returns a collection of BootstrapTourStep objects.
*
* #return Collection[BootstrapTourStep]|null
*/
public function getBootstrapTourSteps(): ?Collection
{
return $this->bootstrapTourSteps;
}
/**
* Adds a Step to the tour.
*
* #return BootstrapTour
*/
public function addBootstrapTourStep(BootstrapTourStep $bootstrapTourStep): BootstrapTour
{
$bootstrapTourStep->setBootstrapTour($this);
$this->bootstrapTourSteps[] = $bootstrapTourStep;
return $this;
}
BootstrapTourStep.php
/**
* #var int
*
* #ORM\Column(name="id", type="integer", options={"unsigned"=true})
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
* #JMS\Groups({"auth_read_getbootstraptours"})
* #JMS\Type("integer")
* #JMS\Accessor(getter="getId")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="BootstrapTour", inversedBy="bootstrapTourSteps")
* #ORM\JoinColumn(name="tour_id", referencedColumnName="id", nullable=false)
*
* #JMS\Groups({"auth_read_postbootstraptours"})
* #JMS\Type("EN\CentralAdmin\DoctrineBundle\Entity\BootstrapTour")
* #JMS\Accessor(getter="getBootstrapTour", setter="setBootstrapTour")
*/
private $bootstrapTour;
/**
* Gets the BootstrapTour
*
* #return BootstrapTour|null
*/
public function getBootstrapTour(): ?BootstrapTour
{
return $this->bootstrapTour;
}
/**
* Sets a BootstrapTour
*
* #param BootstrapTour $bootstrapTour
* #return BootstrapTourStep
*/
public function setBootstrapTour(BootstrapTour $bootstrapTour): BootstrapTourStep
{
$this->bootstrapTour = $bootstrapTour;
return $this;
}
/**
* A list of reference proxies.
*
* #return array
*/
public function getReferenceProxies(): array
{
return [
'BootstrapTour'
];
}
My controller Action :
$bootstrapTourService = $this->getCentralAdminEntityService('BootstrapTour');
$bootstrapTourService->persist($tourType, true);
I am able to select the data using this but in case of adding new record I am getting the following exception:
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'tour_id' cannot be null
How can I resolve this issue?
You're not setting the relation to the tour on the steps when adding a collection of steps. This way the step entities are added to the tour but the steps themselves don't know which tour they belong to.
If now doctrine tries to persist the steps their reference to the tour is missing and therefore you get the missing tour_id exception.
This ...
public function setBootstrapTourSteps(?ArrayCollection $bootstrapTourSteps): BootstrapTour
{
$this->bootstrapTourSteps = $bootstrapTourSteps;
return $this;
}
... should be:
public function setBootstrapTourSteps(?ArrayCollection $bootstrapTourSteps): BootstrapTour
{
$this->bootstrapTourSteps = new ArrayCollection();
foreach ($bootstrapTourSteps as $step) {
$step->setBootstrapTour($this);
$this->bootstrapTourSteps->add($step);
}
return $this;
}

Doctrine Multi-Tenancy Missing Value From Primary Key (With 2 PKs)

I am working on a multi-tenancy system for Doctrine. I ran into an exception that said
Missing value for primary key groupId on ContactBundle\Entity\Contact
The way my multi-tenancy works is by having the data from different organizatiosn seperated by their groupId. That way each organization can have an id=1 and not break any rules because the combination of their groupId and the Id is what makes the record unique.
This means that you can have
record 1:
id = 1
groupId = 1
record 2:
id = 1
groupId = 2
and it would be valid.
The problem that I am running into is the fact that I am not sure how to pass in the groupId for when it goes to do the joins for my associations, so it throws that error. Since the group_id of the currently viewed project should be the same as the ones listed for contact and organization, how would I go about passing the current project's groupId into the query for contact and organization? That way it pulls the right record and doesn't complain about missing a primary key.
Below is my Project Entity listed.
<?php
namespace ProjectBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Project
*
* #ORM\Table(name="project")
* #ORM\Entity(repositoryClass="ProjectBundle\Repository\ProjectRepository")
*/
class Project
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=2500)
*/
private $description;
/**
* #var int
*
* #ORM\OneToOne(targetEntity="ContactBundle\Entity\Contact", inversedBy="projects")
* #ORM\JoinColumn(name="contact_id", referencedColumnName="id")
*
*/
private $contactId;
/**
* #var int
*
* #ORM\OneToOne(targetEntity="ContactBundle\Entity\Organization", inversedBy="projects")
* #ORM\JoinColumn(name="organization_id", referencedColumnName="id")
*/
private $organizationId;
/**
* #var int
*
* #ORM\Column(name="group_id", type="integer")
* #ORM\Id
*/
private $groupId;
public function __construct($id, $groupId){
$this->id = $id;
$this->groupId = $groupId;
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Project
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set description
*
* #param string $description
*
* #return Project
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set contactId
*
* #param integer $contactId
*
* #return Project
*/
public function setContactId($contactId)
{
$this->contactId = $contactId;
return $this;
}
/**
* Get contactId
*
* #return int
*/
public function getContactId()
{
return $this->contactId;
}
/**
* Set organizationId
*
* #param integer $organizationId
*
* #return Project
*/
public function setOrganizationId($organizationId)
{
$this->organizationId = $organizationId;
return $this;
}
/**
* Get organizationId
*
* #return int
*/
public function getOrganizationId()
{
return $this->organizationId;
}
}
I will also give you guys my substitutes for find() & findAll() since my current system requires the groupId to get the right record.
/**
* #param integer $groupId
* #param integer $id
*/
public function findDataCollection(int $groupId)
{
$qb = $this->repository->createQueryBuilder('e');
$qb
->andWhere('e.groupId = :groupId')
->setParameter('groupId',$groupId);
return $qb->getQuery()->getResult();
}
/**
* #param integer $groupId
* #param integer $id
*/
public function findData(int $groupId, $id)
{
if(empty($id)){
return false;
}
$qb = $this->repository->createQueryBuilder('e');
$qb
->andWhere('e.id = :id')
->andWhere('e.groupId = :groupId')
->setParameter('id', $id)
->setParameter('groupId',$groupId);
$data = $qb->getQuery()->getOneorNullResult();
return $data;
}
Thank's lots ahead of time guys!
writing my comments down as an answer as they require somewhat more space here. So nope, I was recommending that: I was recommending that you would replace the second part of your composite key (groupid) to be an actual association to the group entity instead of being a manually managed id field (https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes).
As for your original question, I'm not actually sure what your issue is. If you would have the Project entity available, you can directly access the connected contact and organization via the related getters.
I'm not sure whether your associations are correctly defined for your use case or not; you have defined the associations as one-to-one for your Project, which basically means that in addition to one project having one contact and belonging to one organization, also the other way around that one contact can have only one project and one organization can only have only one project... I.e. they sound like they should be defined as ManyToOne associations (?)

integrity constraint violation 1062 with ORM and Symfony2

I have an Entity with a primary key like this:
/**
* #var integer
*
* #ORM\Column(name="product_id", type="integer", nullable=false)
* #ORM\Id
*/
protected $productId;
....
/**
* Set productId
*
* #param integer $productId
* #return Products
*/
public function setProductId($productId)
{
$this->productId = $productId;
return $this;
}
/**
* Get productId
*
* #return integer
*/
public function getProductId()
{
return $this->productId;
}
But when I try to insert an ProductId with set method, I get this error:
integrity constraint violation 1062 duplicate entry '0' for key 'primary'
I tried with * #ORM\GeneratedValue(strategy="NONE") but the result it's the same, I need to set the Product Id because the sequence isn't 1, 2, 3... is different.
And I can't create a new Id because my current ProductId is used by other entities like Foreing Keys.
Any solution?
Thanks in advance.
-----Edit with the file where I have the error-----
$prod = new Products();
$prod->setProductId("65");
$manager->persist($prod);
$manager->flush();
----Edit with whole Entity----
namespace My\WebBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class Products
{
/**
* #var integer
*
* #ORM\Column(name="product_id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
protected $productId;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=50, nullable=false)
*/
private $name;
/**
* #var integer
*
* #ORM\Column(name="version", type="integer", nullable=true)
*/
private $version;
/**
* #var string
*
* #ORM\Column(name="code", type="string", length=10, nullable=false)
*/
private $code;
/**
* #var integer
*
* #ORM\Column(name="price", type="integer", nullable=false)
*/
private $price;
/**
* Set productId
*
* #param integer $productId
* #return Products
*/
public function setProductId($productId)
{
$this->productId = $productId;
return $this;
}
/**
* Get productId
*
* #return integer
*/
public function getProductId()
{
return $this->productId;
}
/**
* Set name
*
* #param string $name
* #return Products
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set version
*
* #param integer $version
* #return Products
*/
public function setVersion($version)
{
$this->version = $version;
return $this;
}
/**
* Get version
*
* #return integer
*/
public function getVersion()
{
return $this->version;
}
/**
* Set code
*
* #param string $code
* #return Products
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return string
*/
public function getCode()
{
return $this->code;
}
/**
* Set price
*
* #param integer $price
* #return Products
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* #return integer
*/
public function getPrice()
{
return $this->price;
}
When using no identifier generation strategy you should not forget that you have to assign the custom ID before you call EntityManagers persist() method.
I think you are persisting the new Entity before assigning the custom ID which means your $productId property is set to null and will be casted to 0 (zero) if you try to flush it. That will cause your error.
Doctrine Doc
Marcus post a good answer to your problem. You can solve it by adding id into you Entity, and use productId as secondary key.
Add id and set it to Auto increment, like
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
Then you can use your productId with:
/**
* #var integer
*
* #ORM\Column(name="product_id", type="integer", nullable=false)
*/
protected $productId;
With this solution you will use $productId as secondary key. Don't forget to clear data in your table.
You also have an error here:
$prod->setProductId(65);
Now you try set data which is string - in your table is integer.

Overlapped Non Primary Key for Composite Foreign Key Doctrine Symfony 2

I'm trying to construct four entities using Doctrine Symfony 2.
One of the entities has "Overlapped or Intersected Non Primary Key Composite Foreign Key" - apologize for my bad English.
I've tried to modify doctrine object but I can't still persist all the entities to PostgreSQL.
Below the doctrine objects of four entities I've constructed:
<?php
namespace EntityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="EntityBundle\EntityRepository\GeographyContinentRepository")
* #ORM\Table(
* name="geography_continent",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="geography_continent_u1", columns={"continent_name"})
* }
* )
*/
class GeographyContinent
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(name="continent_name", type="string", nullable=false)
*/
protected $continentName;
/**
*
* #ORM\Column(name="description", type="string", nullable=true)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set continentName
*
* #param string $continentName
* #return GeographyContinent
*/
public function setContinentName($continentName)
{
$this->continentName = $continentName;
return $this;
}
/**
* Get continentName
*
* #return string
*/
public function getContinentName()
{
return $this->continentName;
}
/**
* Set description
*
* #param string $description
* #return GeographyContinent
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
}
?>
<?php
namespace EntityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="EntityBundle\EntityRepository\GeographyCountryRepository")
* #ORM\Table(
* name="geography_country",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="geography_country_u1", columns={"country_name"}),
* #ORM\UniqueConstraint(name="geography_country_u2", columns={"telephone_code"}),
* #ORM\UniqueConstraint(name="geography_country_u3", columns={"currency_name"}),
* #ORM\UniqueConstraint(name="geography_country_u4", columns={"currency_symbol"})
* }
* )
*/
class GeographyCountry
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(name="country_name", type="string", nullable=false)
*/
protected $countryName;
/**
*
* #ORM\Column(name="telephone_code", type="string", nullable=true)
*/
protected $telephoneCode;
/**
*
* #ORM\Column(name="currency_name", type="string", nullable=true)
*/
protected $currencyName;
/**
*
* #ORM\Column(name="currency_symbol", type="string", nullable=true)
*/
protected $currencySymbol;
/**
*
* #ORM\Column(name="continent_id", type="integer", nullable=false)
*/
protected $continentId;
/**
*
* #ORM\ManyToOne(targetEntity="GeographyContinent", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="continent_id", referencedColumnName="id")
*/
protected $fkContinent;
/**
*
* #ORM\Column(name="description", type="string", nullable=true)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set countryName
*
* #param string $countryName
* #return GeographyCountry
*/
public function setCountryName($countryName)
{
$this->countryName = $countryName;
return $this;
}
/**
* Get countryName
*
* #return string
*/
public function getCountryName()
{
return $this->countryName;
}
/**
* Set telephoneCode
*
* #param string $telephoneCode
* #return GeographyCountry
*/
public function setTelephoneCode($telephoneCode)
{
$this->telephoneCode = $telephoneCode;
return $this;
}
/**
* Get telephoneCode
*
* #return string
*/
public function getTelephoneCode()
{
return $this->telephoneCode;
}
/**
* Set currencyName
*
* #param string $currencyName
* #return GeographyCountry
*/
public function setCurrencyName($currencyName)
{
$this->currencyName = $currencyName;
return $this;
}
/**
* Get currencyName
*
* #return string
*/
public function getCurrencyName()
{
return $this->currencyName;
}
/**
* Set currencySymbol
*
* #param string $currencySymbol
* #return GeographyCountry
*/
public function setCurrencySymbol($currencySymbol)
{
$this->currencySymbol = $currencySymbol;
return $this;
}
/**
* Get currencySymbol
*
* #return string
*/
public function getCurrencySymbol()
{
return $this->currencySymbol;
}
/**
* Set continentId
*
* #param integer $continentId
* #return GeographyCountry
*/
public function setContinentId($continentId)
{
$this->continentId = $continentId;
return $this;
}
/**
* Get continentId
*
* #return integer
*/
public function getContinentId()
{
return $this->continentId;
}
/**
* Set description
*
* #param string $description
* #return GeographyCountry
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set fkContinent
*
* #param \EntityBundle\Entity\GeographyContinent $fkContinent
* #return GeographyCountry
*/
public function setFkContinent(\EntityBundle\Entity\GeographyContinent $fkContinent = null)
{
$this->fkContinent = $fkContinent;
return $this;
}
/**
* Get fkContinent
*
* #return \EntityBundle\Entity\GeographyContinent
*/
public function getFkContinent()
{
return $this->fkContinent;
}
}
?>
<?php
namespace EntityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="EntityBundle\EntityRepository\GeographyProvinceRepository")
* #ORM\Table(
* name="geography_province",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="geography_province_u1", columns={"country_id", "id"}),
* #ORM\UniqueConstraint(name="geography_province_u2", columns={"country_id", "province_name"})
* }
* )
*/
class GeographyProvince
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(name="province_name", type="string", nullable=false)
*/
protected $provinceName;
/**
* #ORM\Column(name="country_id", type="integer", nullable=false)
*/
protected $countryId;
/**
*
* #ORM\ManyToOne(targetEntity="GeographyCountry", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="country_id", referencedColumnName="id")
*/
protected $fkCountry;
/**
*
* #ORM\Column(name="description", type="string", nullable=true)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set provinceName
*
* #param string $provinceName
* #return GeographyProvince
*/
public function setProvinceName($provinceName)
{
$this->provinceName = $provinceName;
return $this;
}
/**
* Get provinceName
*
* #return string
*/
public function getProvinceName()
{
return $this->provinceName;
}
/**
* Set countryId
*
* #param integer $countryId
* #return GeographyProvince
*/
public function setCountryId($countryId)
{
$this->countryId = $countryId;
return $this;
}
/**
* Get countryId
*
* #return integer
*/
public function getCountryId()
{
return $this->countryId;
}
/**
* Set description
*
* #param string $description
* #return GeographyProvince
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set fkCountry
*
* #param \EntityBundle\Entity\GeographyCountry $fkCountry
* #return GeographyProvince
*/
public function setFkCountry(\EntityBundle\Entity\GeographyCountry $fkCountry = null)
{
$this->fkCountry = $fkCountry;
return $this;
}
/**
* Get fkCountry
*
* #return \EntityBundle\Entity\GeographyCountry
*/
public function getFkCountry()
{
return $this->fkCountry;
}
}
?>
<?php
namespace EntityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="EntityBundle\EntityRepository\GeographyCityRepository")
* #ORM\Table(
* name="geography_city",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="geography_city_u1", columns={"province_id", "is_municipality", "city_name"})
* }
* )
*/
class GeographyCity
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\Column(name="city_name", type="string", nullable=false)
*/
protected $cityName;
/**
*
* #ORM\Column(name="is_municipality", type="boolean", nullable=true)
*/
protected $isMunicipality;
/**
*
* #ORM\Column(name="province_id", type="integer", nullable=true)
*/
protected $provinceId;
/**
*
* #ORM\Column(name="country_id", type="integer", nullable=false)
*/
protected $countryId;
/**
*
* #ORM\ManyToOne(targetEntity="GeographyCountry", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="country_id", referencedColumnName="id", nullable=false)
*/
protected $fkCountry;
/**
*
* #ORM\ManyToOne(targetEntity="GeographyProvince", cascade={"persist", "remove"})
* #ORM\JoinColumns
* (
* {
* #ORM\JoinColumn(name="country_id", referencedColumnName="country_id", nullable=false),
* #ORM\JoinColumn(name="province_id", referencedColumnName="id", nullable=true)
* }
* )
*/
protected $fkProvince;
/**
*
* #ORM\Column(name="description", type="string", nullable=true)
*/
protected $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set cityName
*
* #param string $cityName
* #return GeographyCity
*/
public function setCityName($cityName)
{
$this->cityName = $cityName;
return $this;
}
/**
* Get cityName
*
* #return string
*/
public function getCityName()
{
return $this->cityName;
}
/**
* Set isMunicipality
*
* #param boolean $isMunicipality
* #return GeographyCity
*/
public function setIsMunicipality($isMunicipality)
{
$this->isMunicipality = $isMunicipality;
return $this;
}
/**
* Get isMunicipality
*
* #return boolean
*/
public function getIsMunicipality()
{
return $this->isMunicipality;
}
/**
* Set provinceId
*
* #param integer $provinceId
* #return GeographyCity
*/
public function setProvinceId($provinceId)
{
$this->provinceId = $provinceId;
return $this;
}
/**
* Get provinceId
*
* #return integer
*/
public function getProvinceId()
{
return $this->provinceId;
}
/**
* Set countryId
*
* #param integer $countryId
* #return GeographyCity
*/
public function setCountryId($countryId)
{
$this->countryId = $countryId;
return $this;
}
/**
* Get countryId
*
* #return integer
*/
public function getCountryId()
{
return $this->countryId;
}
/**
* Set description
*
* #param string $description
* #return GeographyCity
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set fkCountry
*
* #param \EntityBundle\Entity\GeographyCountry $fkCountry
* #return GeographyCity
*/
public function setFkCountry(\EntityBundle\Entity\GeographyCountry $fkCountry)
{
$this->fkCountry = $fkCountry;
return $this;
}
/**
* Get fkCountry
*
* #return \EntityBundle\Entity\GeographyCountry
*/
public function getFkCountry()
{
return $this->fkCountry;
}
/**
* Set fkProvince
*
* #param \EntityBundle\Entity\GeographyProvince $fkProvince
* #return GeographyCity
*/
public function setFkProvince(\EntityBundle\Entity\GeographyProvince $fkProvince)
{
$this->fkProvince = $fkProvince;
return $this;
}
/**
* Get fkProvince
*
* #return \EntityBundle\Entity\GeographyProvince
*/
public function getFkProvince()
{
return $this->fkProvince;
}
}
?>
The four entities above able to generate SQL DDL PostgreSQL properly.
Below the generated sql (with few modifications):
CREATE TABLE geography_continent
(
id INT NOT NULL,
continent_name VARCHAR(255) NOT NULL,
description VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
);
CREATE TABLE geography_country
(
id INT NOT NULL,
continent_id INT NOT NULL,
country_name VARCHAR(255) NOT NULL,
telephone_code VARCHAR(255) DEFAULT NULL,
currency_name VARCHAR(255) DEFAULT NULL,
currency_symbol VARCHAR(255) DEFAULT NULL,
description VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
);
CREATE TABLE geography_province
(
id INT NOT NULL,
country_id INT NOT NULL,
province_name VARCHAR(255) NOT NULL,
description VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
);
CREATE TABLE geography_city
(
id INT NOT NULL,
country_id INT NOT NULL,
province_id INT DEFAULT NULL,
city_name VARCHAR(255) NOT NULL,
is_municipality BOOLEAN DEFAULT NULL,
description VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
);
CREATE SEQUENCE geography_continent_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE geography_country_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE geography_province_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE geography_city_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE UNIQUE INDEX geography_continent_u1 ON geography_continent (continent_name);
CREATE INDEX IDX_6D7254DD921F4C77 ON geography_country (continent_id);
CREATE UNIQUE INDEX geography_country_u1 ON geography_country (country_name);
CREATE UNIQUE INDEX geography_country_u2 ON geography_country (telephone_code);
CREATE UNIQUE INDEX geography_country_u3 ON geography_country (currency_name);
CREATE UNIQUE INDEX geography_country_u4 ON geography_country (currency_symbol);
CREATE INDEX IDX_1657BF92F92F3E70 ON geography_province (country_id);
CREATE UNIQUE INDEX geography_province_u1 ON geography_province (country_id, id);
CREATE UNIQUE INDEX geography_province_u2 ON geography_province (country_id, province_name);
CREATE INDEX IDX_3F82CFCAF92F3E70 ON geography_city (country_id);
CREATE INDEX IDX_3F82CFCAF92F3E70E946114A ON geography_city (country_id, province_id);
CREATE UNIQUE INDEX geography_city_u1 ON geography_city (province_id, is_municipality, city_name);
ALTER TABLE geography_country ADD CONSTRAINT FK_6D7254DD921F4C77 FOREIGN KEY (continent_id) REFERENCES geography_continent (id) MATCH FULL ON UPDATE CASCADE ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
ALTER TABLE geography_province ADD CONSTRAINT FK_1657BF92F92F3E70 FOREIGN KEY (country_id) REFERENCES geography_country (id) MATCH FULL ON UPDATE CASCADE ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
ALTER TABLE geography_city ADD CONSTRAINT FK_3F82CFCAF92F3E70 FOREIGN KEY (country_id) REFERENCES geography_country (id) MATCH FULL ON UPDATE CASCADE ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
-- MATCH SIMPLE FOREIGN KEY
ALTER TABLE geography_city ADD CONSTRAINT FK_3F82CFCAF92F3E70E946114A FOREIGN KEY (country_id, province_id) REFERENCES geography_province (country_id, id) MATCH SIMPLE ON UPDATE CASCADE ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
Table "geography_city" have two foreign keys.
One refers to table "geography_country" with column "country_id".
The other refers to table "geography_province" with two columns "country_id" and "province_id", column "province_id" is optional and may NULL (signed as "MATCH SIMPLE" FOREIGN KEY) because perhaps A City of A Country does not have province.
Below main php code of the controller to persist the four entities above:
<?php
$geographyContinentName = "A Continent Name";
$geographyContinent = new GeographyContinent();
$geographyContinent->setContinentName($geographyContinentName);
$geographyCountryName = "A Country Name";
$geographyCountry = new GeographyCountry();
$geographyCountry->setCountryName($geographyCountryName);
$geographyCountry->setFkContinent($geographyContinent);
$geographyProvinceName = "A Province Name";
$geographyProvince = new GeographyProvince();
$geographyProvince->setProvinceName($geographyProvinceName);
$geographyProvince->setFkCountry($geographyCountry);
$geographyCityName = "A City Name";
$geographyCity = new GeographyCity();
$geographyCity->setCityName($geographyCityName);
$geographyCity->setFkCountry($geographyCountry);
$geographyCity->setFkProvince($geographyProvince);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($geographyContinent);
$entityManager->persist($geographyCountry);
$entityManager->persist($geographyProvince);
$entityManager->persist($geographyCity);
$entityManager->flush();
?>
Below the errors produced after running the controller above:
[2013-12-15 06:41:38] request.INFO:
Matched route "entity_geography_create"
(
parameters:
"_controller": "Entity\GeographyBundle\Controller\CreateController::indexAction",
"_route": "entity_geography_create"
)
[2013-12-15 06:41:38] app.ERROR:
Doctrine\DBAL\DBALException:
An exception occurred while executing
'INSERT INTO geography_city (id, city_name, is_municipality, province_id, country_id, description) VALUES (?, ?, ?, ?, ?, ?)'
with params [1, "A City Name", null, 1, null, null]
SQLSTATE[23502]: Not null violation
ERROR: null value in column "country_id" violates not-null constraint
(uncaught exception) at D:\server\htdocs\application\vendor\doctrine\dbal\lib\Doctrine\DBAL\DBALException.php line 47
I expect that value of column "country_id" will be provided automatically when inserting into table "geography_city", but based on the errors above it does not.
Any help I would really appreciate.
Thank you very much.
Best Regards.
#n.1 Many thanks for your kind help.
My full transaction code running well.
I execute commands:
php app/console doctrine:cache:clear-metadata
php app/console doctrine:cache:clear-query
php app/console doctrine:cache:clear-result
php app/console cache:clear --no-warmup
My problem is solved now.
Thanks God.
I just encountered the same problem and solved it by calling $entityManager->flush(); after every call to $entityManager->persist($your_new_entity);. It will ensure that the persisted entity will have an id, so this id will be available for the other entity which use it as a foreign key.
So you have to call
$entityManager->persist($your_new_entity);
$entityManager->flush();
before using the new entity as a foreign key.
It seems to be feasible by defining cascade operations, see the documentation of Doctrine2 about Persisting entities for more information.

Symfony2's Doctrine does not create one-to-many structure for me

I have two tables. First table is users and second is datas. Datas has useridx column which is foreign with user's idx. (primary unique key).
These are the table structures:
Table users
CREATE TABLE public.users (
idx bigint NOT NULL,
"name" varchar(250) DEFAULT NULL::character varying,
surname varchar(250) DEFAULT NULL::character varying,
isactive boolean NOT NULL DEFAULT false,
/* Keys */
CONSTRAINT users_pkey
PRIMARY KEY (idx),
CONSTRAINT users_idx_key
UNIQUE (idx)
) WITH (
OIDS = FALSE
);
Table datas:
CREATE TABLE public.datas (
idx bigint NOT NULL,
useridx bigint,
phrase varchar(100) DEFAULT NULL::character varying,
response varchar(100) DEFAULT NULL::character varying,
/* Keys */
CONSTRAINT datas_pkey
PRIMARY KEY (idx),
CONSTRAINT datas_idx_key
UNIQUE (idx),
/* Foreign keys */
CONSTRAINT fk_cf180c1a262768b5
FOREIGN KEY (useridx)
REFERENCES public.users(idx)
ON DELETE NO ACTION
ON UPDATE NO ACTION
) WITH (
OIDS = FALSE
);
Now when i run these commands:
app/console doctrine:mapping:convert yml
./src/Acme/DemoBundle/Resources/config/doctrine/metadata/orm
--from-database
--force
And;
app/console doctrine:mapping:import AcmeDemoBundle annotation
app/console doctrine:generate:entities AcmeDemoBundle
I got this result:
Datas.php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\DemoBundle\Entity\Datas
*
* #ORM\Table(name="datas")
* #ORM\Entity
*/
class Datas
{
/**
* #var bigint $idx
*
* #ORM\Column(name="idx", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="datas_idx_seq", allocationSize="1", initialValue="1")
*/
private $idx;
/**
* #var string $phrase
*
* #ORM\Column(name="phrase", type="string", length=100, nullable=true)
*/
private $phrase;
/**
* #var string $response
*
* #ORM\Column(name="response", type="string", length=100, nullable=true)
*/
private $response;
/**
* #var Users
*
* #ORM\ManyToOne(targetEntity="Users")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="useridx", referencedColumnName="idx")
* })
*/
private $useridx;
/**
* Get idx
*
* #return bigint
*/
public function getIdx()
{
return $this->idx;
}
/**
* Set phrase
*
* #param string $phrase
*/
public function setPhrase($phrase)
{
$this->phrase = $phrase;
}
/**
* Get phrase
*
* #return string
*/
public function getPhrase()
{
return $this->phrase;
}
/**
* Set response
*
* #param string $response
*/
public function setResponse($response)
{
$this->response = $response;
}
/**
* Get response
*
* #return string
*/
public function getResponse()
{
return $this->response;
}
/**
* Set useridx
*
* #param Acme\DemoBundle\Entity\Users $useridx
*/
public function setUseridx(\Acme\DemoBundle\Entity\Users $useridx)
{
$this->useridx = $useridx;
}
/**
* Get useridx
*
* #return Acme\DemoBundle\Entity\Users
*/
public function getUseridx()
{
return $this->useridx;
}
}
?>
Users.php
<?php
namespace Acme\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\DemoBundle\Entity\Users
*
* #ORM\Table(name="users")
* #ORM\Entity
*/
class Users
{
/**
* #var bigint $idx
*
* #ORM\Column(name="idx", type="bigint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="users_idx_seq", allocationSize="1", initialValue="1")
*/
private $idx;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=250, nullable=true)
*/
private $name;
/**
* #var string $surname
*
* #ORM\Column(name="surname", type="string", length=250, nullable=true)
*/
private $surname;
/**
* #var boolean $isactive
*
* #ORM\Column(name="isactive", type="boolean", nullable=false)
*/
private $isactive;
/**
* Get idx
*
* #return bigint
*/
public function getIdx()
{
return $this->idx;
}
/**
* Set name
*
* #param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set surname
*
* #param string $surname
*/
public function setSurname($surname)
{
$this->surname = $surname;
}
/**
* Get surname
*
* #return string
*/
public function getSurname()
{
return $this->surname;
}
/**
* Set isactive
*
* #param boolean $isactive
*/
public function setIsactive($isactive)
{
$this->isactive = $isactive;
}
/**
* Get isactive
*
* #return boolean
*/
public function getIsactive()
{
return $this->isactive;
}
}
?>
I also have yml files but i dont think they are necessary in here only PHP files i posted here.
Now, when i run this command inside of my controller:
<?php
$user = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Users')
->find(24);
$phrase = $user->getDatas()->getPhrase();
?>
I got an error that say Call to a member function getDatas() on a non-object.... I know it is clear. In Users.php i don't have getDatas().
But what i read from Symfony2 and Doctrine documentation is it should be there because they are related. All i want to do is get Datas inside of Users.
What is my mistake here? What im missing?
Update:
I added this lines to the Users.php
<?php
/**
* #var \Acme\DemoBundle\Entity\Datas
*
* #ORM\OneToMany(targetEntity="Datas", mappedBy="datas", cascade={"all"})
*/
private $datas;
public function __construct()
{
$this->datas = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add phrases
*
* #param Acme\DemoBundle\Entity\Datas $datas
*/
public function addPhrases(\Acme\DemoBundle\Entity\Datas $datas)
{
$this->datas[] = $datas;
}
/**
* Get datas
*
* #return Doctrine\Common\Collections\Collection
*/
public function getDatas()
{
return $this->datas;
}
?>
And these lines to the Datas.php
<?php
/**
* #ORM\ManyToOne(targetEntity="Users", inversedBy="users", cascade={"all"})
*/
protected $users;
/**
* Set users
*
* #param Acme\DemoBundle\Entity\Users $users
*/
public function setUsers(\Acme\DemoBundle\Entity\Users $users)
{
$this->users = $users;
}
/**
* Get users
*
* #return Acme\DemoBundle\Entity\Users
*/
public function getUsers()
{
return $this->users;
}
?>
Now getDatas() is working but inside of it is not. ($user->getDatas()->getPhrase();)
I am getting this error:
Call to undefined method Doctrine\ORM\PersistentCollection::getPhrase()
Conclusion: I got collection error because it returns a collection -of course-. Iterate (like foreach) it and you will access the data. (If you encounter a problem like this.)
If look at the documentation of #JoinColumn
This annotation is used in the context of relations in #ManyToOne, #OneToOne fields and in the Context of #JoinTable nested inside a #ManyToMany. This annotation is not required. If its not specified the attributes name and referencedColumnName are inferred from the table and primary key names.
So as you are using ManyToOne relation your relation definition would be,
/**
* #var Users
*
* #ORM\ManyToOne(targetEntity="Users")
* #ORM\JoinColumn(name="useridx", referencedColumnName="idx")
*/
private $useridx;
Edit:
If you want to get datas from user side then you have to create OneToMany relation. e.g
In Datas.php
/**
* #var Users
*
* #ORM\ManyToOne(targetEntity="Users", inversedBy = "datas")
* #ORM\JoinColumn(name="useridx", referencedColumnName="idx")
*/
private $useridx;
And in Users.php add following line,
/**
* #ORM\OneToMany(targetEntity="Datas", mappedBy="useridx", cascade={"persist"})
*/
protected $datas;
And then do a doctrine:generate:entities command. To do operations on relation check this doc entry.

Categories