refers to the inverse side field which does not exist. Doctrine2 - php

I'm working on a OneToOne join in doctrine2/symphony 2.8.2 and I keep getting:
The association X\BaseDesignBundle\Entity\SessionDesign#user refers to the inverse side field X\UserBundle\Entity\User#SessionDesign which does not exist.
User:
/**
* #ORM\OneToOne(targetEntity="X\BaseDesignBundle\Entity\SessionDesign")
* #ORM\JoinColumn(name="fcid", referencedColumnName="id")
*/
private $sessionDesign;
Session Design:
/**
* #ORM\OneToOne(targetEntity="x\UserBundle\Entity\User")
* #ORM\JoinColumn(name="id", referencedColumnName="fcid")
*/
private $user;
I have 0 idea whats wrong at this point and I have tried everything I can think of. Thanks for any help you can give.

JoinColumn should only appear on the entity where the FK is.
E.g (assuming FK is on Session Design.)
Session Design
/**
* #ORM\OneToOne(targetEntity="X\BaseDesignBundle\Entity\User")
* #ORM\JoinColumn(name="fcid", referencedColumnName="id")
*/
private $user;
User:
/**
* #ORM\OneToOne(targetEntity="x\UserBundle\Entity\SessionDesign", inversedBy="user")
*/
private $sessionDesign;
For your own sanity I would recommend naming your FK better. fcid doesn't mean much at a glance, why not call it user_id or session_design_id (depending on where you put the FK).
E.g. * #ORM\JoinColumn(name="session_design_id", referencedColumnName="id")
It just makes things easier to parse
See the documentation for more info.

I would add to previous answer:
#ORM\OneToOne(targetEntity="X\BaseDesignBundle\Entity\User", mappedBy="sessionDesign")

Related

Use UniqueEntity on a Gedmo\Blameable field

I am using Gedmo extension in addition with Symfony 3.2 and Doctrine 2.5.6 and I'm encountering an issue. I can't make Gedmo\Blameable and UniqueEntity constraint work together. Indeed, the blamed field is still null at validation time. Is there any way to make it work or a possible work-around ?
Here is my entity
/**
* #UniqueEntity(
* fields={"author", "question"},
* errorPath="question",
* message="This author already has an answer for that Question"
* )
* #ORM\Entity
*/
class TextAnswer
{
/**
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* #Gedmo\Blameable(on="create")
*/
private $author;
/**
* #Assert\NotNull()
* #ORM\ManyToOne(targetEntity="Question", inversedBy="textAnswers")
* #ORM\JoinColumn(name="question_id", referencedColumnName="id")
*/
private $question;
}
Thanks
EDIT : SOLUTION
Rather than manually setting the user (which removes Gedmo\Blameable interests), I created my own entity validator.
I give it doctrine and token storage as arguments so it can make a query on db to validate my criteria with the currently connected user (that will be later used by Gedmo\Blameable).
The BlameableListener is invoked during the Doctrine's flush operation, which normally happens after the entity has been validated. That's why $author is null at validation time.
The most straightforward workaround is to set $author yourself beforehand.

Relation migrating after targetEntity changed in ManyTone

I changed this code
/**
* #ORM\ManyToOne(targetEntity="Comiti\UserBundle\Entity\Member", fetch="EAGER")
* #ORM\JoinColumn(name="member_id", referencedColumnName="id")
*/
protected $member;
By
/**
* #ORM\ManyToOne(targetEntity="Comiti\UserBundle\Entity\User", fetch="EAGER")
* #ORM\JoinColumn(name="member_id", referencedColumnName="id")
*/
protected $member;
I need now migrate the old Member ids to the good User ids. Unfortunately, i can't find a way to get old ids i tried
$subscription->getMember()->getId()
which is null
i tried too
$subscription->getMemberId()
Thks for help
Do you renamed the Entity Member to User and kepp the same mysql (or whatever) table or do you change mysql table too?
If you change table, you have to play directly with your dbrm to upgrade your data.

Entity class mapping is invalid

Hi i am trying to create a OneToMany relationship between Page and Block tables but i am getting the following error on validating the schema:
[Mapping] FAIL - The entity-class 'mypath\Entity\Block' mapping is invalid:
* The association mypath\Entity\Block#pages refers to the inverse side field mypath\Entity\Page#blocks which does not exist.
[Mapping] FAIL - The entity-class 'mypath\Entity\Page' mapping is invalid:
* The association mypath\Entity\Page#block refers to the owning side field mypath\Entity\Block#page which does not exist.
Following are my page and Block Entities
Page:
/**
* #ORM\OneToMany(targetEntity="Block", mappedBy="page")
*/
private $block;
Block:
/**
* #ORM\ManyToOne(targetEntity="Page", inversedBy="block")
* #ORM\JoinColumn(referencedColumnName="id")
*/
private $pages;
I am not sure what wrong with it but seems to be something related to annotations. Please help, Thanks !!!
Ok i found the solution. The problem was with the names.
So if we read it in normal terms, it make sense.
A page can have many blocks. So page entity will be
/**
* #ORM\OneToMany(targetEntity="Block", mappedBy="pages")
*/
private $blocks;
Similarly, a block belongs to many pages. So block entity will be
/**
* #ORM\ManyToOne(targetEntity="Page", inversedBy="blocks")
* #ORM\JoinColumn(referencedColumnName="id")
*/
private $pages;
targetEntity will always be the class name which would be singular and field names will be plural(in case of OneToMany and may be in other cases as well).
That resolves the issue. Have a good day !!!
In the annotation, you call the properties "blocks and "page", but they're called "block" and "pages" in the actual code.
Page:
/**
* #ORM\OneToMany(targetEntity="Block", mappedBy="page")
*/
private $blocks;
Block:
/**
* #ORM\ManyToOne(targetEntity="Page", inversedBy="blocks")
*/
private $page;

Symfony Association Mapping OneToOne and OneToMany to Same Entity

I have a View entity that represents the primary page record, and then I have an associated entity called ViewVersion which stores multiple versions of the entity as it's changed over time. The View entity sets the current "Published" ViewVersion in the VersionId field. This makes for a simple OneToOne association. But in some contexts I will also want to get all the versions associated with this View entity, e.g. if I want to allow the user to review older versions and revert back. So I will need another mapping which is a OneToMany. The first viewVersion will map to the active "published" version, and the second viewVersions will show all the versions.
Entity Definitions
/**
* #ORM\Entity
* #ORM\Table(name="view")
* #ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewRepository")
*/
class View extends Entity\Base {
/**
* #ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", inversedBy="view", cascade={"persist", "remove"}, orphanRemoval=true)
* #ORM\JoinColumn(name="versionId", referencedColumnName="id")
*/
protected $viewVersion;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $versionId = NULL;
/**
* #ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="viewAll", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $viewVersions;
}
/**
* #ORM\Entity
* #ORM\Table(name="view_version")
* #ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewVersionRepository")
*/
class ViewVersion extends Entity\Base {
/**
* #ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", mappedBy="viewVersion", cascade={"persist"})
*/
protected $view;
/**
* #ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="viewVersions")
* #ORM\JoinColumn(name="viewId", referencedColumnName="id")
*/
protected $viewAll;
/**
* The primary view entity that this version belongs to.
* #ORM\Column(type="integer", nullable=true)
*/
protected $viewId;
}
This "works" but is it recommended to have two associations with the same entity like this? Or is this a really bad idea?
The ViewVersion entity will reference a single View entity in both cases, but the mapped associations need two separate variables, e.g. View and ViewAll. I'm not exactly sure how the internals work for the association, and how the reference variable with the mapping is used.
Alternatively, I could get rid of the OneToOne association, and just set a ViewRepository function to get the current published version based on the versionId (just like the old mapped entity used to do with the getVersion()). That would work, but is it more internal overhead, because it would make two queries... or will Doctrine be smart enough to optimize this, just like it did with the getVersion().
NOTE:
These other answers are not complete.
References:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html
http://doctrine-orm.readthedocs.org/en/2.0.x/reference/association-mapping.html#one-to-many-bidirectional
Typically, I have found the best approach is to solve this in a different way.
One common pattern I have seen before is you use a single table to hold all records, and have an 'active' flag.
If your query to select the active one works like so:
SELECT * FROM table WHERE active = true ORDER BY updated_at DESC LIMIT 1;
Then enabling a new one becomes as simple as:
UPDATE table SET active = 1, updated_at = '<timestamp>' WHERE id = <new id>;
UPDATE table SET active = 0, updated_at = '<timestamp>' WHERE id = <old id>;
Your new page will be active as soon as the first query hits, and your second query will avoid any sort of weirdness as that row will already be no longer active.
If you have other models that depend on a consistent ID to reference, then another route which also maintains some sanity would be to have one table for the active entries (in whole, not in part) and then a second table with additional metadata to track versions.
The latter approach could be nicely handled via Doctrine's inheritance system (http://docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html) which would let you define the base View class, and then for the "ViewRevision" model, extend View and add a "Revised on" type timestamp.
Per the advice from #jmather I've decided this model is "okay", because I need a single View entity that other entities can access (e.g. Routing urls that point to a single View, i.e. "page").
I've changed the OneToOne relationship for View to be unidirectional only, because the ViewVersion already has an association back to the View via the other OneToMany (so it doesn't need two paths back).
This allows me to keep a simple method for $view->getPublished() handy and seems more logical.
/**
* #ORM\Entity
* #ORM\Table(name="view")
*/
class View extends Entity\Base {
/**
* This is a OneToOne Unidirectional association, just so that we can get the
* current published version easily, based on the publishedId.
* #ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\TestVersion")
* #ORM\JoinColumn(name="publishedId", referencedColumnName="id")
*/
protected $published;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $publishedId = NULL;
/**
* This is the regular OneToMany Bi-Directional Association, for all the versions.
* #ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="view", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $versions;
}
/**
* #ORM\Entity
* #ORM\Table(name="view_version")
*/
class ViewVersion extends Entity\Base {
/**
* #ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="versions")
* #ORM\JoinColumn(name="viewId", referencedColumnName="id")
*/
protected $view;
/**
* The primary view entity that this version belongs to.
* #ORM\Column(type="integer", nullable=true)
*/
protected $viewId;
}
However, I've discovered that as long as the $view->publishedId is set the view can't be deleted from the database because of foreign key constraints (even though it's uni-directional). So I have to break that foreign key link before removing. I think that's fine. I posted details about that here: Overlapping Entity Association causing Database Foreign Key Constraint Errors when Removing Entity

Persisting entity with Doctrine association

I'm having trouble trying to persist an entity with an association using Doctrine.
Here's the mapping on my owning side: (User.php)
/** #Role_id #Column(type="integer") nullable=false */
private $role_id;
/**
* #ManyToOne(targetEntity="Roles\Entities\Role")
* #JoinColumn(name="role_id", referencedColumnName="id")
*/
private $role;
There's no mapping on the inverse side, I tried with (OneToMany) and it didn't seem to make a difference.
Basically, I'm passing a default value of 2 (integer) to a method setRole_id but it shows up as blank when I actually go to persist the entity which causes a MySQL error as that column doesn't allow nulls.
Edit 1:
Literally just persisting this for role_id
$this->user->setRole_id( 2 );
Cheers,
Ewan
Your mapping seems incorrect. Try to rewrite it as follows:
/**
* #ManyToOne(targetEntity="Roles\Entities\Role")
* #JoinColumn(name="role_id", referencedColumnName="id", nullable=false)
*/
private $role;
In other words, you only need to describe the role_id as the join column of your relationship. You don't need to map it as a "normal" column. Then just write and use a regular setter declared like the one below:
public function setRole(Roles\Entities\Role $role) {
$this->role = $role;
}
Use the above instead of $this->user->setRole_id(2) and persist your user entity. Doctrine should automatically take care of storing the correct entity ID in the foreign key field for you.

Categories