I'm encountering a strange problem using Doctrine2.
I'm getting the following error:
doctrine orm:validate-schema
[Mapping] FAIL - The entity-class 'EmailVerification' mapping is invalid:
* The referenced column name 'id' does not have a corresponding field with this
column name on the class 'OurUsers'.
[Database] OK - The database schema is in sync with the mapping files.
My scenario is as follows:
I have 3 tables sharing a primary key.
Table Auth which holds user_id PK.
Table OurUsers for which Auth.user_id is shared PK.
Table EmailVerification for which OurUsers.user_id is shared PK.
I also have NotOurUsers - hence the split.
Entities are declared as follows:
/**
* #Entity
* #Table(name="auth")
*/
class Auth {
/** #Id #Column(type="integer", name="user_id") #GeneratedValue #var int */
private $id;
/* ... */
}
/**
* #Entity
* #Table(name="our_users")
*/
class OurUsers {
/**
* #Id
* #OneToOne(targetEntity="Auth")
* #JoinColumn(nullable=false, name="user_id", referencedColumnName="user_id")
* #var Auth
*/
private $id;
/* ... */
}
/**
* #Entity
* #Table(name="email_verification")
*/
class EmailVerification {
/**
* #Id
* #OneToOne(targetEntity="OurUsers")
* #JoinColumn(nullable=false, name="user_id", referencedColumnName="user_id")
* #var OurUsers
*/
private $id;
/* ... */
}
I'm using Dosctrine 2.1.
btw Doctrine 2.2 validates mappings as good, but I get same error at run time as with 2.1.
I think the problem is that EmailVerfication points to OurUSers intead of to Auth, the error message is misleading though. I am not sure the triple mapping is possible from the internals (i am pretty sure i implemented an exception for this some where as well, i have to look why this is not triggered).
You tell in your JoinColumn statements that you work with a user_id column.
But your column definition for OurUser::id creates a id column by default.
You either have to modify the JoinColumn statement to use id:
/**
* #Entity
* #Table(name="email_verification")
*/
class EmailVerification {
/**
* #Id
* #OneToOne(targetEntity="OurUsers")
* #JoinColumn(nullable=false, name="user_id", referencedColumnName="id")
* #var OurUsers
*/
private $id;
/* ... */
}
OR
add a Column annotation on OurUser::id, like that:
/**
* #Entity
* #Table(name="our_users")
*/
class OurUsers {
/**
* #Id
* #OneToOne(targetEntity="Auth")
* #Column(type="integer", name="user_id")
* #JoinColumn(nullable=false, name="user_id", referencedColumnName="user_id")
* #var Auth
*/
private $id;
/* ... */
}
I think it would be better to switch to something like this, it's a lot more clear and should create less problems:
/**
* #Entity
* #Table(name="auth")
*/
class Auth {
/** #Id #Column(type="integer", name="user_id") #GeneratedValue #var int */
private $id;
/* ... */
}
/**
* #Entity
* #Table(name="our_users")
*/
class OurUsers {
/**
* #Id
* #GeneratedValue
*/
private $id;
/**
* #OneToOne(targetEntity="Auth")
* #var Auth
*/
private $auth;
/* ... */
}
/**
* #Entity
* #Table(name="email_verification")
*/
class EmailVerification {
/**
* #Id
* #GeneratedValue
*/
private $id;
/**
* #OneToOne(targetEntity="OurUsers")
* #var OurUsers
*/
private $ourUser;
/* ... */
}
Related
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.
I try to use #MappedSuperclass. It works well for simple variable (int, string...) and OneToMany/ManyToOne relationship. But OneToOne relationship doesn't work.
I have two MappedSuperclass with OneToOne relationship :
_SiteUser
/**
* #MappedSuperclass _SiteUser
*
* #ORM\Entity(repositoryClass="_SiteModule\_Repository\_SiteUserRepository")
* #ORM\Table(name="site_users")
*/
class _SiteUser
{
/**
* #var int
* #Groups("id")
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #Groups({"username"})
*
* #ORM\Column(name="username", type="string", length=255, unique=true)
*/
protected $username;
/**
* #var string
* #Groups({"password"})
*
* #ORM\Column(name="password", type="string", length=255)
*/
protected $password;
/**
* #var _SiteUserTo
*
* #ORM\OneToOne(targetEntity="_SiteModule\_Entity\_SiteUserTo", mappedBy="user")
* #Gedmo\Versioned()
*/
protected $user_to;
_SiteUserTo
/**
* #MappedSuperclass _SiteUserTo
*
* #ORM\Entity(repositoryClass="_SiteModule\_Repository\_SiteUserToRepository")
* #ORM\Table(name="users_to")
*/
class _SiteUserTo
{
/**
* #var int
* #Groups("id")
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var _SiteUser
*
* #ORM\OneToOne(targetEntity="_SiteModule\_Entity\_SiteUser", inversedBy="user_to")
* #JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
And this is my 2 class who extends these MappedSuperclass :
SiteUser
/**
* SiteUser
*
* #ORM\Entity(repositoryClass="SiteModule\Repository\SiteUserRepository")
* #ORM\Table(name="site_users")
*/
class SiteUser extends _SiteUser
{
}
SiteUserTo
/**
* SiteUserTo
*
* #ORM\Entity(repositoryClass="SiteModule\Repository\SiteUserToRepository")
* #ORM\Table(name="users_to")
*/
class SiteUserTo extends _SiteUserTo
{
}
When I generate entities from my MappedSuperclass (_SiteUser and _SiteUserTo), I got well a table named "users_to" with id and user_id. But when I generate entities from my others classes (SiteUser and SiteUserTo), it creates the table "users_to" with only id field. I don't know why...
If I update my SiteUser Class like this :
/**
* Class SiteUser
*
* #ORM\Entity(repositoryClass="SiteModule\Repository\SiteUserRepository")
* #ORM\Table(name="site_users")
*/
class SiteUser extends _SiteUser
{
/**
* #var boolean
*
* #ORM\Column(name="test", type="boolean")
*/
protected $test;
/**
* #var SiteUserTo
*
* #ORM\OneToOne(targetEntity="SiteModule\Entity\SiteUserTo", mappedBy="user")
*/
protected $user_to;
}
And SiteUserTo like this :
/**
* Class SiteUserTo
*
* #ORM\Entity(repositoryClass="SiteModule\Repository\SiteUserToRepository")
* #ORM\Table(name="users_to")
*/
class SiteUserTo extends _SiteUserTo
{
/**
* #var boolean
*
* #ORM\Column(name="test", type="boolean")
*/
protected $test;
/**
* #var SiteUser
*
* #ORM\OneToOne(targetEntity="SiteModule\Entity\SiteUser", inversedBy="user_to")
* #JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
}
I got the same problem, no field user_id in table users_to. But the field "test" is well created in the table site_users and in the table users_to...
A mapped superclass cannot be an entity, it is not query-able and
persistent relationships defined by a mapped superclass must be
unidirectional (with an owning side only). This means that One-To-Many
associations are not possible on a mapped superclass at all.
Furthermore Many-To-Many associations are only possible if the mapped
superclass is only used in exactly one entity at the moment. For
further support of inheritance, the single or joined table inheritance
features have to be used.
Simply said you can not have #MappedSuperClass and #ORM\Entity annotations at the same time, hence the unexpected results
https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html
I'm trying to implement a doctrine relation for a symphony 3 app.
I have two different classes, one extending from the other, which are related to the same entity with a many to one relation.
Here are my classes.
Country.php
class Country
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Groups({"exposed"})
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Link", mappedBy="country")
*/
private $link;
/**
* #ORM\OneToMany(targetEntity="LinkChild", mappedBy="country")
*/
private $linkChild;
public function __construct()
{
$this->link = new ArrayCollection();
$this->linkChild = new ArrayCollection();
}
}
Link.php
/**
* Link
*
* #ORM\Table(name="link")
* #ORM\Entity(repositoryClass="Decathlon\AppCollaboratorBundle\Reposito\LinkRepository")
* #Vich\Uploadable
* #ORM\HasLifecycleCallbacks()
*/
class Link
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Serializer\Groups({"link_list", "link_info"})
* #Serializer\Expose()
*/
protected $id;
/**
* #var Country
*
* #ORM\ManyToOne(targetEntity="Country", inversedBy="link", cascade={"persist"})
* #JoinColumn(name="country_id", referencedColumnName="id")
*/
protected $country;
}
LinkChild.php
/**
* #ORM\Entity(repositoryClass="Decathlon\AppCollaboratorBundle\Repository\LinkChildRepository")
*/
class LinkChild extends Link
{
/**
* #var Country
*
* #ORM\ManyToOne(targetEntity="Country", inversedBy="linkChild", cascade={"persist"})
* #JoinColumn(name="country_id", referencedColumnName="id")
*/
protected $country;
}
I need to create a relation between both Link and LinkChild to Country but no country column is created in LinkChild table.
I've told not to use recursive classes so I must create Link and LinkChild.
Is there a way to acomplish what I'm tryng to do.
Thank you in advance.
I think what you are looking for is single table inheritance?
<?php
namespace MyProject\Model;
/**
* #Entity
* #InheritanceType("SINGLE_TABLE")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
*/
class Person
{
// ...
}
/**
* #Entity
*/
class Employee extends Person
{
// ...
}
Take a look here:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html#single-table-inheritance
Try renaming your protected $country; variable to something like private $childCountry; to make it a variable that belongs specifically to LinkChild.
Your protected $country; override in LinkChild is ignored because it is exactly the same as the one in Link.
I got this error from my UserRepository:
[Semantical Error] line 0, col 51 near 'h': Error: Class DokMngr\Entity\User has no association named id
I understand that the error comes from the missing declaration inside my user entity. I can not find a correct syntax when a field is both a generated id and a OneToMany association.
Hope somebody can help me to solve my problem or at least explain why I can't use an id as an association.
class UserRepository extends EntityRepository
{
public function findAllwithHistoryCount() {
$qb = $this->createQueryBuilder('u')
->leftJoin('u.id', 'h');
return $qb->getQuery()->getResult();
}
}
/**
* #Entity(repositoryClass="DokMngr\Repository\UserRepository")
* #Table(name="users")
*/
class User implements UserInterface
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
protected $id;
}
/**
* #Entity(repositoryClass="DokMngr\Repository\HistoryRepository")
* #Table(name="history")
*/
class History
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
protected $id;
/**
* #ManyToOne(targetEntity="User", inversedBy="id")
* #JoinColumn(name="user", referencedColumnName="id")
*/
protected $user;
}
Thanks to Olibiaz I found my error in reasoning.
I thought the whole time that I have to create an association between User.id and History.user like inside the database.
But instead I have to create a new field histories in my User entity. (which exactly not exist inside the database)
So here's the corrected entities:
User
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity(repositoryClass="DokMngr\Repository\UserRepository")
* #Table(name="users")
*/
class User implements UserInterface
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
protected $id;
/**
* #OneToMany(targetEntity="History", mappedBy="user")
*/
private $histories;
}
History
/**
* #Entity(repositoryClass="DokMngr\Repository\HistoryRepository")
* #Table(name="history")
*/
class History
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
protected $id;
/**
* #ManyToOne(targetEntity="User", inversedBy="histories")
* #JoinColumn(name="user", referencedColumnName="id")
*/
protected $user;
}
I have the following situation:
/**
* #Entity
* #Table(name="users")
*/
class Users{
/**
*
* #Id #Column(type="integer")
* #GeneratedValue
*/
protected $id_user;
/**
* #OneToMany(targetEntity="Items",mappedBy="user")
*/
private $items;
//this method sould return distinct items by name or group by name
public function getItems(){
return $this->items;
}
}
/**
* #Entity
* #Table(name="items")
*/
class Items{
/**
*
* #Id #Column(type="integer")
* #GeneratedValue
*/
protected $id_item;
/**
*
* #Id #Column(type="string")
*/
protected $name;
/**
* #ManyToOne(targetEntity="User",inversedBy="items")
* #JoinColumn(name="id_user", referencedColumnName="id_user" ,onDelete="CASCADE")
*/
protected $user;
}
In my view i send an $UserEntity, my problem is that i want to display only items that have unique name.
So If i do $items=$userEntity->getItems(); i receive all user items, not only unique one.
How can i solve this situation?
Thanks
select distinct with DQL should do the trick