I am looking for some help as to why my OneToMany relationship in doctrine only returns one value. My data model has three tables. Users, Authorization, and Applications. The Authorization table is the glue that maps users to applications and also contains an accesslevel field to indicate their level of access for that application.
I have a user that has three entries in authorization for three different applications, but for some reason, doctrine is only loading 1 of those authorization records. I've included my full data model below. The attribute in question is "authorization" in the Webusers table.
Anyone know what I am doing wrong?
class Webusers {
/**
* #var integer
*
* #ORM\Column(name="userid", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $userid;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Applications", mappedBy="userid")
*/
private $applications;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\OneToMany(targetEntity="Authorization", mappedBy="user")
*/
private $authorization;
/**
* Constructor
*/
public function __construct() {
$this->applications = new \Doctrine\Common\Collections\ArrayCollection();
$this->authorization = new \Doctrine\Common\Collections\ArrayCollection();
}
class Authorization {
/**
* #var integer
*
* #ORM\Column(name="accesslevel", type="integer", nullable=false)
*/
private $accesslevel;
/**
* #var integer
*
* #ORM\Column(name="applicationid", type="integer", nullable=false)
* $ORM\Id
*/
private $applicationid;
/**
* #var integer
*
* #ORM\Column(name="userid", type="integer", nullable=false)
* #ORM\Id
*/
private $userid;
/**
* #var \Webusers
*
* #ORM\ManyToOne(targetEntity="Webusers")
* #ORM\JoinColumn(name="userid", referencedColumnName="userid")
*/
private $user;
}
class Applications {
/**
* #var integer
*
* #ORM\Column(name="applicationid", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $applicationid;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=50, nullable=false)
*/
private $name;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Webusers", inversedBy="applicationid")
* #ORM\JoinTable(name="authorization",
* joinColumns={
* #ORM\JoinColumn(name="applicationid", referencedColumnName="applicationid")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="userid", referencedColumnName="userid")
* }
* )
*/
private $userid;
/**
* Constructor
*/
public function __construct()
{
$this->userid = new \Doctrine\Common\Collections\ArrayCollection();
}
}
I was able to fix this by making sure I specified both the webusers and application relationship as ManyToOne AND giving them the #ORM\Id property since they make up a composite primary key.
I think the main reason this was failing was because I had not associated authorization to applications.
The key points of my new model are as follows:
class Webusers {
/**
* #var \Doctrine\Common\Collections\Collection
* #ORM\OneToMany(targetEntity="Authorization", mappedBy="user")
*/
private $authorization;
}
class Authorization {
/**
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Applications")
* #ORM\JoinColumn(name="applicationid", referencedColumnName="applicationid")
*/
private $application;
/**
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Webusers")
* #ORM\JoinColumn(name="userid", referencedColumnName="userid")
*/
private $user;
}
class Applications {
/**
* #ORM\OneToMany(targetEntity="Authorization", mappedBy="application")
*/
private $authorization;
}
Related
I have ClassA mapped to the entity ClassB with ManyToOne relation (simple so far).
class ClassA{
/**
* #var string
* #ORM\Id
* #ORM\Column(name="keyA", type="string", length=255)
*/
private $keyA;
/**
* #var ClassB $classB
* #ORM\ManyToOne(targetEntity="ClassB", inversedBy="classAs")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="ClassB_keyB", referencedColumnName="keyB")
* })
*/
private $classB;
}
And this is the ClassB:
class ClassB{
/**
* #var string
* #ORM\Id
* #ORM\Column(name="keyB", type="string", length=255)
*/
private $keyB;
/**
*
* #var ClassC $classC
* #ORM\Id
* #ORM\ManyToOne(targetEntity="ClassC", inversedBy="classBs")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="ClassC_keyC", referencedColumnName="keyC")
* })
*/
private $classC;
/**
* #var ArrayCollection $classAs
* #ORM\OneToMany(targetEntity="ClassA", mappedBy="classB")
*/
private $classAs;
}
As you can notice the ClassB contains a composite primary key (2 entities and on column).
And this is the ClassC:
class ClassC{
/**
* #var string
* #ORM\Id
* #ORM\Column(name="keyC", type="string", length=255)
*/
private $keyC;
/**
* #var ArrayCollection $classBs
* #ORM\OneToMany(targetEntity="ClassB", mappedBy="classC")
*/
private $classBs;
}
Whene i try to display all entities of ClassA (using findAll()) I get this exception Missing value for primary key classC on ERP\................\ClassB
What am I missing here ?!
you have to create your own method at ClassARepository and add your join columns
I have next entities:
/**
* Customer
*
* #ORM\Table(name="customer")
* #ORM\Entity()
*/
class Customer
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Account[]|ArrayCollection
*
* #ORM\OneToMany(targetEntity="Account", mappedBy="customer")
*/
private $accounts;
/**
* #var Account
*
* #ORM\OneToOne(targetEntity="Account")
*
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id",referencedColumnName="customer_id"),
* #ORM\JoinColumn(name="default_account_id", referencedColumnName="id")
* })
*/
private $defaultAccount;
}
/**
* Account
*
* #ORM\Table(name="account")
*/
class Account
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Customer
*
* #ORM\ManyToOne(targetEntity="Customer", inversedBy="accounts")
* #ORM\JoinColumn(nullable=false)
*/
private $customer;
}
Idea that customer has multiply accounts, onr of the account should be default for customer. I would like to use foreign key with multiply fields to ensure that default customer account belongs to this customer, but I'm getting next error:
Column name `customer_id` referenced for relation from MyBundle\Entity\Customer towards MyBundle\Entity\Account does not exist.
Actually there is no "customer_id" field on ORM level, because it is "customer.id" but I dont know how to reference it.
It seems that line #ORM\JoinColumn(name="id",referencedColumnName="customer_id"), is redundant. Try to configure this field as following:
/**
* #var Account
*
* #ORM\OneToOne(targetEntity="Account")
*
* #ORM\JoinColumn(name="default_account_id", referencedColumnName="id")
*/
private $defaultAccount;
By the way, I think it would be better if you just added a boolean column is_default into your Account entity.
How can I do this?
My Entities:
Product entity
/**
* #ORM\Entity
* #ORM\Table(name="products")
*/
class Product
{
/**
* #ORM\Id()
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #var int
*/
private $id;
/**
* #ORM\Column(type="string", length=512)
* #var string
*/
private $name;
/**
* (??)
* #var ArrayCollection
*/
private $images;
}
Article entity
/**
* #ORM\Entity
* #ORM\Table(name="articles")
*/
class Article
{
/**
* #ORM\Id()
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #var int
*/
private $id;
/**
* #ORM\Column(type="string", length=512)
* #var string
*/
private $title;
/**
* (??)
* #var ArrayCollection
*/
private $images;
}
Image entity
/**
* #ORM\Entity
* #ORM\Table(name="images")
*/
class Image
{
/**
* #ORM\Id()
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #var int
*/
private $id;
/**
* #ORM\Column(type="string", length=512)
* #var string
*/
private $name;
/**
* #ORM\Column(type="string", length=1024)
* #var string
*/
private $path;
}
I don't know how to create a link tables with additional fields like the picture. Which association should I use? How to manage these relations in entities?
Usually when you need a many to many approach Doctrine let you define such behaviour with a simple annotation.
#ORM\ManyToMany(targetEntity="full_qualified_namespace")
#ORM\JoinTable(
name="game_schemas_players",
joinColumns={#ORM\JoinColumn(name="this_field_name", referencedColumnName="id")},
inverseJoinColumns={#ORM\JoinColumn(name="that_field_anem", referencedColumnName="id")}
)
This will instruct Doctrine to create a relation the current entity and the target entity.
But that's not your case. For what I can see from your model you need to add some field on the 'middle' entity.
Here what you may want to do:
class Product
{
[...]
/**
* #var ArrayCollection | ProductImage[]
*
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="product")
*/
private $productImages;
}
class Image
{
[...]
/**
* #var ArrayCollection | ProductImage[]
*
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="image")
*/
private $productImages;
}
as you can see as defined here either Product and Image have a oneToMany relation with a middle entity which will be named ProductImage**.
The last step will be to implement such entity:
class ProductImage
{
[...]
/**
* #var Image
*
* #ORM\ManyToOne(targetEntity="Image", mappedBy="image")
* #ORM\JoinColumn(name="image_id", referencedColumnName="id")
*/
private $image;
/**
* #var Product
*
* #ORM\ManyToOne(targetEntity="Product", mappedBy="product")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
*/
private $product;
/**
* #ORM\Column(type="string", length=1024)
* #var string
*/
private $position;
}
The owning side of the relation both for Product and Image is still ProductImage.
As a side note in your entity is common practice to implement an add method in this fashion:
public function __contructor(){
$this->productImages = new ArrayCollection();
}
/**
* Add ProductImage
*
* #param ProductImage $productImage
* #return $this
*/
public function addDocument(ProductImage $productImage)
{
$productImage->addProductImage($productImage);
$this->documents->add($document);
return $this;
}
and then you can use such method with the following approach:
$product = new Product();
$image = new Image();
$productImage = new ProductImage($product,$image);
$product->addProductImage($productImage);
Don't forget to provide the usual setter method as Doctrine need them to initialize the entity.
Hope it helps, Regards.
I have a problem with Doctrine2 it throws me this exception:
An exception occurred while executing 'INSERT INTO sesion (Contrasena, Estado, UsuarioIdentificacion) VALUES (?, ?, ?)' with params ["j15474874654j", "1", null]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'UsuarioIdentificacion' cannot be null
I am a beginner with doctrine 2 and I could not resolve this error, I think the error is in relationships. I've read other similar problems, but I have not succeeded.
I would greatly appreciate the help. this is my code:
In my controller:
$usuario = new Usuario();
$data = $request->getPost();
$usuario->setNombre($data['nombre']);
$usuario->setApellidos($data['apellidos']);
$usuario->setIdentificacion($data['identificacion']);
$usuario->setTitulo($data['titulo']);
$usuario->setContacto($data['contacto']);
$usuario->setCorreo($data['correo'] . "#correounivalle.edu.co");
$sesion = new Sesion();
$sesion->setUsuarioidentificacion($usuario);
$sesion->setEstado("1");
$sesion->setContrasena($data['nombre'][0].$data['identificacion'].$data['apellidos'][0]);
$em->persist($usuario);
$em->persist($sesion);
$em->flush();
class usuario:
<?php
namespace DBAL\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Usuario
*
* #ORM\Table(name="usuario", uniqueConstraints={#ORM\UniqueConstraint(name="Identificacion", columns={"Identificacion"}), #ORM\UniqueConstraint(name="Correo", columns={"Correo"})})
* #ORM\Entity
* #ORM\Entity(repositoryClass="DBAL\Repository\UsuarioRepository")
*/
class Usuario
{
/**
* #var integer
*
* #ORM\Column(name="Id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="Identificacion", type="integer", nullable=false)
*/
private $identificacion;
/**
* #var string
*
* #ORM\Column(name="Nombre", type="string", length=50, nullable=false)
*/
private $nombre;
/**
* #var string
*
* #ORM\Column(name="Apellidos", type="string", length=50, nullable=false)
*/
private $apellidos;
/**
* #var string
*
* #ORM\Column(name="Correo", type="string", length=100, nullable=false)
*/
private $correo;
/**
* #var integer
*
* #ORM\Column(name="Contacto", type="integer", nullable=true)
*/
private $contacto;
/**
* #var string
*
* #ORM\Column(name="Titulo", type="string", length=20, nullable=true)
*/
private $titulo;
/*with their respective setter and getter*/
class sesion:
<?php
namespace DBAL\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Sesion
*
* #ORM\Table(name="sesion", indexes={#ORM\Index(name="UsuarioIdentificacion", columns={"UsuarioIdentificacion"}), #ORM\Index(name="sesion", columns={"UsuarioIdentificacion"})})
* #ORM\Entity
*/
class Sesion
{
/**
* #var integer
*
* #ORM\Column(name="Id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="Contrasena", type="string", length=50, nullable=false)
*/
private $contrasena;
/**
* #var boolean
*
* #ORM\Column(name="Estado", type="boolean", nullable=false)
*/
private $estado;
/**
* #var \Usuario
*
*
* #ORM\OneToOne(targetEntity="Usuario")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="UsuarioIdentificacion", referencedColumnName="Correo")
* })
*/
private $usuarioidentificacion;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Roles", mappedBy="sesionusuarioidentificacion")
*/
private $rolesid;
/**
* Constructor
*/
public function __construct()
{
$this->rolesid = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set contrasena
*
* #param string $contrasena
*
* #return Sesion
*/
public function setContrasena($contrasena)
{
$this->contrasena = $contrasena;
return $this;
}
/**
* Get contrasena
*
* #return string
*/
public function getContrasena()
{
return $this->contrasena;
}
/**
* Set estado
*
* #param boolean $estado
*
* #return Sesion
*/
public function setEstado($estado)
{
$this->estado = $estado;
return $this;
}
/**
* Get estado
*
* #return boolean
*/
public function getEstado()
{
return $this->estado;
}
/**
* Set usuarioidentificacion
*
* #param \DBAL\Entity\Usuario $usuarioidentificacion
*
* #return Sesion
*/
public function setUsuarioidentificacion(\DBAL\Entity\Usuario $usuarioidentificacion)
{
$this->usuarioidentificacion = $usuarioidentificacion;
return $this;
}
/**
* Get usuarioidentificacion
*
* #return \Usuario
*/
public function getUsuarioidentificacion()
{
return $this->usuarioidentificacion;
}
/**
* Add rolesid
*
* #param \Roles $rolesid
*
* #return Sesion
*/
public function addRolesid(\Roles $rolesid)
{
$this->rolesid[] = $rolesid;
return $this;
}
/**
* Remove rolesid
*
* #param \Roles $rolesid
*/
public function removeRolesid(\Roles $rolesid)
{
$this->rolesid->removeElement($rolesid);
}
/**
* Get rolesid
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getRolesid()
{
return $this->rolesid;
}
If someone could help me, I really need it and I have already searched a lot and attempted in many ways, but really not fix it.
I am working on a product catalog, and have two entities, PcatSalesItem and PcatCategory with a many-to-many relationship between them. If I delete a category, and there are still sales items associated with it, I want an exception to be thrown, I do NOT want cascading delete. On the RDBMS level (PostgreSQL), in the join table, I have set the foreign keys to "ON DELETE RESTRICT". However, when I delete a category that has sales items, Doctrine does a cascading delete. Nowhere have I specified cascade=remove to Doctrine!
Here are the entities:
/**
* PcatSalesItem
*
* #ORM\Table(name="pcat_sales_item")
* #ORM\Entity
* #Gedmo\Loggable(logEntryClass="Qi\Bss\BaseBundle\Entity\Business\LogEntryBusiness")
*/
class PcatSalesItem
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="pcat_sales_item_id_seq", allocationSize=1, initialValue=1)
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=64, nullable=false)
* #Gedmo\Versioned
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=true)
* #Gedmo\Versioned
*/
private $description;
/**
* #var array $categories
*
* #ORM\ManyToMany(targetEntity="PcatCategory")
* #ORM\JoinTable(name="pcat_category_x_sales_item",
* joinColumns={#ORM\JoinColumn(name="sales_item_id", referencedColumnName="id", onDelete="RESTRICT")},
* inverseJoinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id", onDelete="RESTRICT")}
* )
*/
private $categories;
...
}
/**
* PcatCategory
*
* #ORM\Table(name="pcat_category")
* #ORM\Entity
* #Gedmo\Loggable(logEntryClass="Qi\Bss\BaseBundle\Entity\Business\LogEntryBusiness")
*/
class PcatCategory
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="pcat_category_id_seq", allocationSize=1, initialValue=1)
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=64, nullable=false)
* #Gedmo\Versioned
*/
private $name;
/**
* #var array $salesItems
*
* #ORM\ManyToMany(targetEntity="PcatSalesItem")
* #ORM\JoinTable(name="pcat_category_x_sales_item",
* joinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id", onDelete="RESTRICT")},
* inverseJoinColumns={#ORM\JoinColumn(name="sales_item_id", referencedColumnName="id", onDelete="RESTRICT")}
* )
*/
private $salesItems;
....
}
Here is the code I use to delete a category:
$em = $this->getDoctrine()->getManager();
$cat = $em->getRepository('QiBssBaseBundle:PcatCategory')->find(15);
$em->remove($cat);
$em->flush();
Any help will be greatly appreciated!