I am upgrading from doctrine 2.3 to 2.5 and some of the relationships have broken.
I had a look other stack overflow questions. But there is only one id annotation is these classes and the join columns are named after their db column names, not their variable name on the entity
/**
* #Entity
* #Table(name="iso_country_shipping_display")
*/
class IsoCountryShippingDisplay {
/**
* #Id
* #GeneratedValue
* #Column(name="iso_country_shipping_display_id", type="integer", nullable=false)
*/
private $id;
/**
* #ManyToOne(targetEntity="namespace\Website")
* #JoinColumn(name="website_id", referencedColumnName="base_website_id", nullable=false, unique=false)
* #var Website
*/
private $baseWebsite;
/**
* #var IsoCountry
* #ManyToOne(targetEntity="namespace\IsoCountry")
* #JoinColumn(name="iso_3", referencedColumnName="iso_3", nullable=false, unique=false)
*/
private $isoCountry;
/**
* #return IsoCountry
*/
public function getIsoCountry()
{
return $this->isoCountry;
}
}
/**
* #Entity
* #Table(name="iso_country")
*/
class Website
{
/**
* #Id
* #Column(name="website_id", type="integer", nullable=false)
* #var integer
* #GeneratedValue
*/
protected $id;
/**
* #return int
*/
public function getId()
{
return $this->id;
}
}
I got the error message Missing value for primary key id on namespace\Website. I am not sure why I am getting this on doctrine 2.5 but not on 2.3.
Add * #GeneratedValue value annotation to the Website Entity.
Related
I am trying to add a ManyToOne column to an already existing table with rows in it.
I want it to be nullable=false!
Since it is not nullable, I'm trying to set a default value, but there is no option to do it.
If I don't set a default value, the shema update crashes and is not able to create the foreign key since there is no row with id of 0 in the table I created
The code of the table refered by the foreign key:
<?php
namespace MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints;
/**
* #ORM\Table(name="authority")
* #ORM\Entity()
*/
class Authority
{
/**
* #var int
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #Constraints\NotBlank(message="name cannot be blank.")
* #ORM\Column(type="string")
*/
protected $name;
/**
* #var \DateTime
*
* #ORM\Column(name="created_at", type="datetime", nullable=true)
*/
protected $createdAt;
/**
* Authority constructor.
*/
public function __construct()
{
$this->createdAt = new \DateTime();
}
}
The code of the table where I want to add the foreign key:
/**
* #var Authority
* #ORM\ManyToOne(targetEntity="MyBundle\Entity\authority", cascade={"persist"})
* #ORM\JoinColumn(referencedColumnName="id", nullable=false)
*/
protected $authority;
I tried:
protected $authority = 1;
or
* #ORM\JoinColumn(referencedColumnName="id", nullable=false, default=1)
or
public function __construct()
{
$this->authority = 1;
}
I don't want to have to change the database manually.
/**
* #var Authority
* #ORM\ManyToOne(targetEntity="MyBundle\Entity\authority", cascade={"persist"})
* #ORM\JoinColumn(referencedColumnName="id", nullable=false, columnDefinition="INT DEFAULT 1")
*/
protected $authority;
This do the trick in auto generated migration class.
You can set the default for the primary key of the referenced table. Look at the options={"default"=1}:
/**
* #ORM\Table(name="authority")
* #ORM\Entity()
*/
class Authority
{
/**
* #var int
* #ORM\Id
* #ORM\Column(type="integer", options={"default"=1})
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
#ORM\ManyToOne(targetEntity="App\Entity\Enumeration\TypeCompte")
#ORM\JoinColumn(name="IdTypeCompte", referencedColumnName="Id", nullable=false, columnDefinition="INT DEFAULT 1")
*/
private $typeCompte;
Am having a bit of a challenge creating entity relationship between a product its Category and associated color(s) with the following Entities (I omitted the getters and setters though):
#Product
/**
* Product
*
* #ORM\Table(name="product")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository")
*/
class Product
{
/**
* #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;
/**
* #var float
*
* #ORM\Column(name="price", type="float")
*/
private $price;
/**
* #var int
*
* #ORM\Column(name="category", type="integer")
*
* Many Products have one category
*
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=false)
*/
protected $category;
/**
* #var int
*
* Many Products have one color
*
* #ORM\ManyToOne(targetEntity="Color", inversedBy="products")
* #ORM\JoinColumn(name="color_id", referencedColumnName="id")
*
* #ORM\Column(name="color", type="integer")
*/
private $color;
}
#Category
/**
* Category
*
* #ORM\Table(name="category")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
*/
class Category
{
/**
* #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=170, unique=true)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="desc", type="string", length=170, nullable=true)
*/
private $description;
/**
* One Category has many products assigned to it
*
* #ORM\OneToMany(targetEntity="Product", mappedBy="category", cascade={"persist"})
*/
private $products;
/**
* Class Constructor
*
* #param None
* #return void
**/
public function __construct()
{
$this->products = new ArrayCollection();
}
}
#Color
class Color{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="color", type="string", length=191, unique=true)
*/
private $color;
/**
* #var string
*
* #ORM\Column(name="code", type="string", length=191, unique=true)
*/
private $hexcode;
/**
* One Color has many products assigned to it
*
* #ORM\OneToMany(targetEntity="Product", mappedBy="color", cascade={"persist"})
*/
private $products;
/**
* Class Constructor
*
* #param none
* #return void
**/
public function _construct(){
$this->products = new ArrayCollection();
}
}
When I run:
* php bin/console doctrine:schema:validate:
I get the error messages:
* The association AppBundle\Entity\Category#products refers to the owning
side field AppBundle\Entity\Product#category which is not defined as
association, but as field.
* The association AppBundle\Entity\Category#products refers to the owning
side field AppBundle\Entity\Product#category which does not exist.
and:
* The association AppBundle\Entity\Color#products refers to the owning side
field AppBundle\Entity\Product#color which is not defined as association,
but as field.
* The association AppBundle\Entity\Color#products refers to the owning side
field AppBundle\Entity\Product#color which does not exist.
I noticed that whenever I comment out the lines:
** #ORM\Column(name="category", type="integer")
** #ORM\Column(name="color", type="integer")
The above errors vanish but I get a new message and error saying:
** [Mapping] OK - The mapping files are correct.
** [Database] FAIL - The database schema is not in sync with the current
mapping file.
What could i be doing wrong, am new to the doctrine concept, and i have followed the documentations. Any help would be appreciated...
For the Doctrine ORM the relations are not Integers but Entity objects.
Remove The #ORM\Column annotations from all fields with relations (in each entity).
Then update your database schema in development environment with:
php bin/console doctrine:schema:update --force
Then generate a doctrine migration file to execute on your production server
php bin/console doctrine:migrations:generate
Update the generetad migration file to your needs
And execute him by this way
php bin/console doctrine:migrations:execute timestampOfTheMigrateFile
I got a ParentClass like this
/** #ORM\MappedSuperclass */
class BaseValue
{
/**
* #var int
*
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var field
* #ORM\OneToMany(targetEntity="Field", mappedBy="value", cascade="all")
*/
protected $field;
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return field
*/
public function getField()
{
return $this->field;
}
/**
* #param field $field
*/
public function setField($field)
{
$this->field = $field;
}
}
And a child like this
* #ORM\Entity
* #ORM\Table(name="integers")
*/
class Integer extends BaseValue
{
/**
* #var integer
*
* #ORM\Column(name="value", type="integer", nullable=true)
*/
protected $value;
/**
* #return string
*/
public function getValue()
{
return $this->value;
}
/**
* #param string $value
*/
public function setValue($value)
{
$this->value = $value;
}
}
Now I would like to relate the child in another class like this
* #ORM\Entity
* #ORM\Table(name="fields")
*/
class Field
{
/**
* #var int
*
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var
* #ORM\ManyToOne(targetEntity="BaseValue", mappedBy="field", cascade="all")
* #ORM\JoinColumn(name="vid", referencedColumnName="id")
*/
protected $value; // but it does not work
It always gets me the following error:
[Doctrine\Common\Annotations\AnnotationException]
[Creation Error] The annotation #ORM\ManyToOne declared on property zmpim\Entity\Field::$value does not have a property named "mappedBy". Available properties: targetEntity, cascade, fetch, inversedBy
Both got mappedby,.. so the error seems to be senseless
Update:
A field has got values and labels. The values get inherited from BaseValue into IntegerValue, StringValue and later others...
My OneToMany Relation is a parent class of inheritance.
like this, now:
/** #ORM\MappedSuperclass */
class BaseValue
{
/**
* #var int
*
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var Field
* #ORM\OneToMany(targetEntity="Field", mappedBy="field", cascade="persist", orphanRemoval=true )
*/
protected $field;
And this is my ManyToOne:
/**
*
* #ORM\Entity
* #ORM\Table(name="fields")
*/
class Field
{
/**
* #var int
*
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var int|null
* #ORM\ManyToOne(targetEntity="BaseValue", inversedBy="value")
* #ORM\JoinColumn(name="vid", referencedColumnName="id", onDelete="CASCADE")
*/
protected $value;
It still give me an error, but now it is:
[Doctrine\ORM\ORMException]
Column name id referenced for relation from zmpim\Entity\Field towards zmpim\Entity\BaseValue does not exist.
Your Entity Field is the inversed side of your mapping so instead of using MappedBy declaration you have to use this
/**
* Inversed side
* #var int|null
* #ORM\ManyToOne(targetEntity="BaseValue", inversedBy="field")
* #ORM\JoinColumn(name="[your_name]", referencedColumnName="[id]", onDelete="CASCADE")
*/
protected $value;
To understand well inversedSide and MappedBy attributes you can read this:
Doctrine inverse and owning side
After reading again you are aware of your relationnal problem between the two of your entities, but if you declare ManyToOne annotation, you have to set inversedBy attribute or you'll get an error. And this is what you have.
You can't declare ManyToOne annotation with mappedBy attribute because it does not exist and throw an exception by Doctrine.
To resume :
ManyToOne association =>
* #ORM\ManyToOne(targetEntity="[yourEntity]", inversedBy="[Field]")
Be careful this side require the declaration of this :
* #ORM\JoinColumn(name="[your_name]", referencedColumnName="[id]", onDelete="CASCADE")
OneToMany =>
* #ORM\OneToMany(targetEntity="[An_Entity]",
* mappedBy="[Field]", cascade={"persist"}, orphanRemoval=true)
EDIT from your answer :
Your mapping is still incorrect, your data in InversedBy And mappedBy need to be switched.
I have entity developer and comment and relationship Many comment to One developer. And I need form when I see all comment for developer and edit - add, delete in DB . What are the solutions to this problem
entity Comment:
class Comments
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Developer", inversedBy="comments")
* #ORM\JoinColumn(name="talent_id", nullable = true, referencedColumnName="id")
* */
protected $talent;
/**
* #var string
*
* #ORM\Column(name="added_by", type="string", length=10, nullable=true)
*/
private $added_by;
/**
* #var string
*
* #ORM\Column(name="comment", type="string", length=10, nullable=true)
*/
private $comment;
entity Developer:
class Developer extends CustomUser
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/////
/**
* #ORM\OneToMany(targetEntity="Comments", mappedBy="talent", cascade={"persist", "remove"})
*/
protected $comments;
Maybe need form in form but how to do this?
You are looking for field type collection.
Example usage of collection type
class Comments
{
....
/**
*
*#ORM\ManyToOne(targetEntity="Developer", inversedBy="developer_to_comments")
* #ORM\JoinColumn(name="developer_to_comments_id", referencedColumnName="id", nullable=false)
*
*/
private $comments_to_developer;
...
}
And class Developer
class Developer extends CustomUser
{
....
/**
*
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="Comments", mappedBy="comments_to_developer", cascade={"remove"})
*/
private $developer_to_comments;
public function __construct()
{
$this->developer_to_comments = new ArrayCollection();
}
....
}
And don't forget use Doctrine\Common\Collections\ArrayCollection
I've a problem with a composite primary key on a OneToOne relation in Doctrine. When one object has no relation (which is normally possible) I got the following error message:
Doctrine\Common\Proxy\Exception\OutOfBoundsException: Missing value for
primary key idEngine on Farkas\CoreBundle\Entity\Engine
I've found the problem directly in Doctrine:
vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php Line 2116
// TODO: Is this even computed right in all cases of composite keys?
foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) {
$joinColumnValue = isset($data[$srcColumn]) ? $data[$srcColumn] : null;
if ($joinColumnValue !== null) {
if ($targetClass->containsForeignIdentifier) {
$associatedId[$targetClass->getFieldForColumn($targetColumn)] = $joinColumnValue;
} else {
$associatedId[$targetClass->fieldNames[$targetColumn]] = $joinColumnValue;
}
}
}
$joinColumnValue is null when the foreign key is empty because the array $data which includes the row data doesn't have the array key for the relation field. The todo comment tells me that something is wrong with composite keys?
Here my two Entities (just a small test, don't think about the logic of my entities^^):
1st
/**
* Car
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Farkas\CoreBundle\Entity\CarRepository")
*/
class Car
{
/**
* #var integer
*
* #ORM\Column(name="id_car", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $idCar;
/**
* #var string
*
* #ORM\Column(name="brand", type="string", length=255)
*/
private $brand;
/**
* #var string
*
*
* #ORM\OneToOne(targetEntity="Engine", mappedBy="car")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="engine", referencedColumnName="id_engine"),
* #ORM\JoinColumn(name="country", referencedColumnName="country")
* )
*/
private $engine;
/**
* #var integer
* #ORM\Id
* #ORM\Column(name="country", type="integer")
*/
private $country;
}
2nd
/**
* Engine
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Farkas\CoreBundle\Entity\EngineRepository")
*/
class Engine
{
/**
* #var integer
*
* #ORM\Column(name="id_engine", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $idEngine;
/**
* #var string
*
* #ORM\Column(name="engineName", type="string", length=255)
*/
private $engineName;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=255)
*/
private $description;
/**
* #var integer
* #ORM\Id
* #ORM\Column(name="country", type="integer")
*/
private $country;
/**
* #var integer
*
* #ORM\OneToOne(targetEntity="Car", inversedBy="engine")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="car_id", referencedColumnName="id_car"),
* #ORM\JoinColumn(name="country", referencedColumnName="country")
* )
*/
private $car;
}
When I try to execute findAll() I got the error message above. When I execute the generated SQL directly in MySQL, everything looks fine:
SELECT t0.id_car AS id_car1, t0.brand AS brand2, t0.country AS country3,
t0.engine AS engine4, t0.country AS country5 FROM Car t0
It means, the hydration can't work with an empty oneToOne relation.
(Posted on behalf of the OP.)
As expected it was just an error from my side. This is the solution:
Car Entity
/**
* #var string
*
*
* #ORM\OneToOne(targetEntity="Engine", mappedBy="car")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="fk_engine", referencedColumnName="id_engine"),
* #ORM\JoinColumn(name="fk_engine_country", referencedColumnName="country")
* )
*/
private $engine;
Engine Entity
/**
* #var integer
*
* #ORM\OneToOne(targetEntity="Car", inversedBy="engine")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="fk_car", referencedColumnName="id_car"),
* #ORM\JoinColumn(name="fk_car_country", referencedColumnName="country")
* )
*/
private $car;
The name of the join column is an attribute which will be created as relation fields inside the db. I already had an attribute with the name country inside the table. So finally the name is always the foreign key to identify the relation.