OneToOne relationship in Doctrine2 ORM and Symfony - php

I have two entity called PictureTag and Tag, here's the relationship:
/**
* #ORM\Entity
* #ORM\Table(name="picture_tag")
* #ORM\HasLifecycleCallbacks()
*/
class PictureTag
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*
* #ORM\OneToOne(targetEntity="App\MainBundle\Entity\Tag", inversedBy="id")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id", nullable=false)
*/
private $tag;
}
/**
* #ORM\Entity
* #ORM\Table(name="tag")
* #ORM\HasLifecycleCallbacks()
*/
class Tag
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\ManyToOne(targetEntity="App\MainBundle\Entity\PictureTag", inversedBy="tag")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #ORM\Column(name="tag", type="string", nullable=true)
*/
private $tag;
}
Basically I wanted the tag table to contain all the unique tags, so there are no duplicate in the tag. And i wanted picturetag to have a joincolumn that points to the id of the tag. So here's my code in the controller:
foreach ($image->tags as $tag) {
$existingTag = $em->getRepository('AppMainBundle:InstagramTag')->findOneByTag($tag);
$instaPictureTag = new PictureTag();
if ($existingTag) {
$instaPictureTag->setTag($existingTag);
} else {
$instagramTag = new Tag();
$instagramTag->setTag($tag);
$em->persist($instagramTag);
$instaPictureTag->setTag($instagramTag);
}
$instaPictureTag->setPicture($instaShopPicture);
$em->persist($instaPictureTag);
}
So the relationship is basically:
One picture is going to have many tags. And one tag will belong to many pictures.
Picture tag here is the intermediary table.
Basically I am doing a check if the tag already exists in the tag table, if it is then I set the picturetag to be associated with this tag, if not then create one. However doing so generates the following error:
Fatal error: Call to a member function setValue() on a non-object in /Users/MyName/Sites/App/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 2625
Any idea why this is?

As I understand, you want implement OneToMany bidirectional relation between PictureTag and Tag.
Please try:
/**
* #ORM\Entity
* #ORM\Table(name="picture_tag")
* #ORM\HasLifecycleCallbacks()
*/
class PictureTag
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="DynamicSolutions\Bundle\ProsAndConsBundle\Entity\Tag", inversedBy="pictureTags")
* #ORM\JoinColumn(name="tag_id", referencedColumnName="id", nullable=false)
*/
private $tag;
}
/**
* #ORM\Entity
* #ORM\Table(name="tag")
* #ORM\HasLifecycleCallbacks()
*/
class Tag
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="PictureTag", mappedBy="tag")
*/
private $pictureTags;
/**
* #var string
* #ORM\Column(name="tag", type="string", nullable=true)
*/
private $tag;
}

Related

Small error but I don't see where - Symfony Foreign keys

Hey guys i have an error (i think that i do a really idiot error but i don't see were) trying to waste time i ask you the question. The error is that my foreign keys is incorrectly formed. Cannot be more precise ... Thx to all people who will try to answer or search :p
My UserInterestEntity :
/**
* UserInterest
*
* #ORM\Table(name="user_interest", indexes {#ORM\Index(name="userInterest_category_id_fk", columns={"category_id"})})
* #ORM\Entity
*/
class UserInterest
{
/**
* #var \AppBundle\Entity\Category
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Category")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
* })
*/
private $category;
}
My Category Entity :
/**
* UserInterest
*
* #ORM\Table(name="Category", uniqueConstraints {#ORM\UniqueConstraint(name="category_id_uindex", columns={"id"})})
* #ORM\Entity
*/
class Category
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #ORM\OneToOne(targetEntity="UserInterest", inversedBy="Category")
*/
protected $id;
The error is that when i do : php bin/console doctrine:schema:update --force tat tells me : Foreign key constraint is incorrectly formed
The relation must not be mapped on the ID but on a separate property. On the category class you can create an userIntrests property defining the userIntrests that have this category. In example:
class Category
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="UserInterest", mappedBy="category")
*/
protected $intrests;
}
class UserIntrest
{
/**
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="intrests")
*/
protected $category;
}
Use this for reference https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/association-mapping.html#one-to-many-bidirectional

doctrine:schema:update not creating OneToOne relations

When I run the following command: php app/console doctrine:schema:update --force --dump-sql
It returns this message: Nothing to update - your database is already in sync with the current entity metadata.
I have two Entities, User and UserProfile.
User.php
/**
* #ORM\Table(name="users", options={"charset":"utf8mb4", "collate":"utf8mb4_unicode_ci"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\OneToOne(targetEntity="UserProfile", inversedBy="user_id")
*/
private $id;
...
UserProfile.php
/**
* #ORM\Table(name="users_profiles", options={"charset":"utf8mb4", "collate":"utf8mb4_unicode_ci"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserProfileRepository")
*/
class UserProfile
{
/**
* #ORM\Id
* #ORM\Column(name="user_id", type="integer")
* #ORM\OneToOne(targetEntity="User", mappedBy="id")
*/
private $userId;
...
I've already tried clearing the cache.
UPDATE #1
User.php
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\OneToOne(targetEntity="UserProfile", mappedBy="userId")
*/
private $id;
UserProfile.php
/**
* #ORM\Id
* #ORM\Column(name="user_id", type="integer")
* #ORM\OneToOne(targetEntity="User", inversedBy="id")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $userId;
You have a couple of options here, if you want a bi-direction association, meaning you want to be able to access the other entity from either of them then you will want to use another property( NOT the $id) to accomplish this. Something like:
/**
* #ORM\Table(name="users", options={"charset":"utf8mb4", "collate":"utf8mb4_unicode_ci"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="UserProfile", mappedBy="userId")
*/
private $profile;
...
}
Then in UserProfile.php
/**
* #ORM\Table(name="users_profiles", options={"charset":"utf8mb4", "collate":"utf8mb4_unicode_ci"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserProfileRepository")
*/
class UserProfile
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="User", inversedBy="profile")
* #ORM\JoinColumn(name="userId", referencedColumnName="id")
*/
private $user;
...
}
This will allow you to do $userProfile->getUser() and also $user->getProfile().
If you want to use the userId as your primary key for the UserProfile table, you can it just involves more work to set that up and you have to explicitly set it in your application. Easier just to reference it on another field.
Unidirectional
User.php
/**
* #ORM\Table(name="users", options={"charset":"utf8mb4", "collate":"utf8mb4_unicode_ci"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
}
UserProfile.php
/**
* #ORM\Table(name="users_profiles", options={"charset":"utf8mb4", "collate":"utf8mb4_unicode_ci"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserProfileRepository")
*/
class UserProfile
{
/**
* #ORM\OneToOne(targetEntity="User", inversedBy="profile")
* #ORM\JoinColumn(name="userId", referencedColumnName="id")
*/
private $user;
...
}
This will only allow you to do $userProfile->getUser(). Likely not what you are looking for. The other unidirectional solution is from the user object towards the UserProfile, like this:
/**
* #ORM\Table(name="users", options={"charset":"utf8mb4", "collate":"utf8mb4_unicode_ci"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="UserProfile", mappedBy="id")
*/
private $profile;
...
}
Then in UserProfile.php
/**
* #ORM\Table(name="users_profiles", options={"charset":"utf8mb4", "collate":"utf8mb4_unicode_ci"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserProfileRepository")
*/
class UserProfile
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
}
This way you can do $user->getProfile().
inversedBy refers to the property, not the database field.
Change inversedBy="user_id" to inversedBy="userId"
You should also use JoinColumn, not Column, and referencedColumnName as per the documentation:
http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-one-unidirectional

Symfony ManyToOne Form add, delete in DB

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

Symfony 2 relations issue

I nead help.
I have 3 entities. Book, Category And BookCategory - book can have multiple categories so i used another table.
I can easily acces Book and Category useing BookCategory table but i dont know how to do this by Book->BookCategory->Category.
class Category
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="text")
*/
private $name;
/**
* #var Category
* #ORM\ManyToOne(targetEntity="Category", inversedBy="Category")
* #ORM\JoinColumn(name="parent", referencedColumnName="id")
*/
private $parent;
class BookCategory
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Book
* #ORM\ManyToOne(targetEntity="Book", inversedBy="BookCategory")
* #ORM\JoinColumn(name="book_id", referencedColumnName="id")
*/
private $bookId;
/**
* #var Category
* #ORM\ManyToOne(targetEntity="Category", inversedBy="BookCategory")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $categoryId;
/**
* #var integer
*
* #ORM\Column(name="priority", type="integer")
*/
private $priority;
class Book
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="title", type="text")
*/
private $title;
/**
* #var string
*
* #ORM\Column(name="author", type="text")
*/
private $author;
/**
* #var float
*
* #ORM\Column(name="price", type="float")
*/
private $price;
How i need to config my entities or how to make my DQL to achive wanted results?
With your code, you only established the relationship from BookCategory to Book. As you said, that enables you to get the Book associated to one BookCategory.
To go the other way and get all BookCategory that belong to one book, you also need to specify this relationship. What you want is a OneToMany relationship from Book to BookCategory.
<?php
//...
use Doctrine\ORM\Mapping\OneToMany;
class Book
{
//...
/**
* #OneToMany(targetEntity="BookCategory", mappedBy="bookId")
*/
private $bookCategories;
//...
}
class BookCategory
{
//...
/**
* #var Book
* #ORM\ManyToOne(targetEntity="Book", inversedBy="bookCategories")
* #ORM\JoinColumn(name="book_id", referencedColumnName="id")
*/
private $bookId;
//...
}
After adding the necessary getters and setters, getBookCategories() will give you an Array with all BookCategory that belong to the Book.
For more details, have a look at the official Symfony2 documentation:
http://symfony.com/doc/current/book/doctrine.html#relationship-mapping-metadata
Edit:
Included use statement. Corrected inversedBy property for bookId.

doctrine oneToOne mapping of one entity with many other entities do not relate those in database schema

I have region entity and regionEmploymentDetails, regionEducationDetails, regionPowerDetails entities which hold regions employment, education and power details. Entities are kept separate because they hold different data. Below are classes,
class Region
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
*#ORM\OneToOne(targetEntity="RegionEducationDetails")
#ORM\JoinColumn(name="region_id", referencedColumnName="id")
**/
private $education_details;
/**
*#ORM\OneToOne(targetEntity="RegionEmploymentDetails")
#ORM\JoinColumn(name="region_id", referencedColumnName="id")
**/
private $employment_details;
/**
*#ORM\OneToOne(targetEntity="RegionPowerDetails")
#ORM\JoinColumn(name="region_id", referencedColumnName="id")
**/
private $power_details;
}
class RegionEducationDetails
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="region_id", type="integer", length=20)
*/
private $region_id;
}
class RegionEmploymentDetails
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="region_id", type="integer")
*/
private $region_id;
}
class RegionPowerDetails
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="region_id", type="integer")
*/
private $region_id;
}
The problem is when I generate schema using command
php app/console doctrine:schema:update --force
It generate database tables but relates Region Entity with Only RegionPowserDetails Entity and does not relate other entities.
It seems it considers only the last mapping and so relates only with the last entity. If I remove Power entity relation it relates with Entity which is before power i.e Employment.
Am I doing anything wrong ? Is there any solution to this problem ?
The region class should be,
class Region {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
private $education_details_id;
/**
*#ORM\OneToOne(targetEntity="RegionEducationDetails")
#ORM\JoinColumn(name="education_details_id", referencedColumnName="id")
**/
private $education_details;
private $employment_details_id;
/**
*#ORM\OneToOne(targetEntity="RegionEmploymentDetails")
#ORM\JoinColumn(name="employment_details_id", referencedColumnName="id")
**/
private $employment_details;
private $power_details_id;
/**
*#ORM\OneToOne(targetEntity="RegionPowerDetails")
#ORM\JoinColumn(name="power_details_id", referencedColumnName="id")
**/
private $power_details;
}

Categories