One to Many & Many To One Relation In Doctrine - php

I have 2 Tables
Users
Messages
And the Structure of Tables:
Users:
Messages:
Now see there are number of users in Users Table and their messages are stored in Messages table identifying by sender_id and receiver_id
How can I make One-To-Many and Many To One Relationship between these two tables or create this SQL Schema using Doctrine/Annotations?

Something like that:
/**
* #ORM\Entity
* #ORM\Table(name="messages")
*/
class Comment
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=5000, nullable=true)
*/
protected $text;
/**
* Author of the comment
*
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User")
* #var User
*/
protected $sender;
/**
*
*
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User")
* #var User
*/
protected $reciever;

Related

ManyToMany Relationship With Type Symfony Doctrine

I have this structure of Entities
class Group
{
/**
* #var int
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private int $id;
/**
* #var string
* #ORM\Column(name="name", type="string", length=50, nullable=false)
*/
private string $name;
}
class GroupUser
{
/**
* #var int
*
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private int $id;
/**
* #var Group
* #ORM\ManyToOne(targetEntity="Group", inversedBy="GroupUser")
* #ORM\JoinColumn(name="group_id", referencedColumnName="id", nullable=false)
*/
private Group $group;
/**
* #var string
* #ORM\Column(type="string", length=50, nullable=false)
*/
private string $type;
/**
* #var int
* #ORM\Column(type="integer", nullable=false)
*/
private int $user;
}
And there are two types of users. Admins and Clients. There's a ManyToMany relationship between Group and User. And the property in GroupUser $type is saving the Class of either Admin or Client and the property $user is saving the id.
id
group_id
user
type
1
1
1
Entity\Admin
2
2
1
Entity\Client
How do I join it using doctrine from the Admin and Client-side? Or maybe someone could point out to some resources how this kind of relationship works on doctrine? As I'm having a hard time googling anything out.
I imagine it could be like a conditional leftJoin, but I can't seem to figure it out.
Normaly, you cannot do that on database, because it not safe.
Why is it not safe? because you can have an id in the user column of userGroup table that refer to nothing as it is not linked.
I will write what you should have done, and how you can achieve what you want using your own method:
What you should have done:
In your UserGroup entities, have 2 columns (admin and client) which are linked to the related entities. They can be null (Client is null and admin contain the id of admin entity if it is an admin and vice versa). Then you can delete the type column
How to achieve what you using your method:
As it cannot be done in the database, you will have to do it in some manager. Have a method getUser which will check on your type attribute and return the associated entity from the current id stored in $user
example:
public function getUserFromGroupUser(GroupUser $groupUser){
if('Entity\Admin' ===$groupUser->getType()){
return $this->adminRepository->find($groupUser->getUser());
}
if('Entity\Client' ===$groupUser->getType()){
return $this->ClientRepository->find($groupUser->getUser());
}
throw new \RuntimeException('the type does not exist');
}

Symfony 2 Doctrine persist Entity with related entities

I have a problem trying to persist a new entity with Symfony 2.7.11 that have a related Entity.
I need to create a Landing that can have many universities so I created 3 tables
landing
landingId (primary Key)
university
universityId (primary Key)
landingUniversity
landingId (both are primary Key) (foreign Key Landing)
universityId (foreign Key University)
And I have just 2 Entities (Landing & University) and a Many To Many relation (unidirectional, because I just want to know the universities added to a landing, so University hasn't got anything about landing)
First, I find each University on my database and I save them. Then I create the new Landing and I add all of them.
$universityRepository = $this->em->getRepository('University');
$universities = array();
foreach ($listUniversities as $universityId){
$university= $cursosRepository->findById($universityId);
$universities[] = $university[0];
}
$newLanding = new Landing();
$newLanding->setName($landing["name"]);
foreach ($universities as $university){
$newLanding->addUniversity($university);
}
$em = $this->getEntityManager();
$em->persist($newLanding);
$em->flush();
And I'm getting this error when symfony executes flush():
Could not resolve type of column "landingId" of class University
What I'm doing wrong?
My Entity:
/**
* Landing
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="LandingRepository")
*/
class Landing
{
/**
* #var integer
*
* #ORM\Column(name="landingid", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=250)
*/
private $name;
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Language")
* #ORM\JoinColumn(name="languageId", referencedColumnName="languageId")
*/
private $languageId;
/**
* #ORM\ManyToMany(targetEntity="University")
* #ORM\JoinTable(name="landingUniversity",
* joinColumns={#ORM\JoinColumn(name="landingId", referencedColumnName="landingId")},
* inverseJoinColumns={#ORM\JoinColumn(name="unversityId", referencedColumnName="unversityId")}
* )
*/
private $universities;
Thank you so much!!!
The error message is really explicit. Your error is here :
joinColumns={#ORM\JoinColumn(name="landingId", referencedColumnName="landingId")}
should be
joinColumns={#ORM\JoinColumn(name="landingId", referencedColumnName="landingid")}
because your Landing entity doesn't contain any landingId database field, but landingid.
But you'd rather edit the column name of your $id property :
/**
* #var integer
*
* #ORM\Column(name="landingId", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

How to add additional columns to a join table in Doctrine2?

I would like to create a notification system. There is a Notification class. A notification can be assigned to more than one users, not just one.
There is a joint table user_notifications, with two columns: user_id and notification_id
The definition of the $notifications in the user class is this:
/**
* #ManyToMany(targetEntity="Notification")
* #JoinTable(name="user_notifications",
* joinColumns={#JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="notification_id", referencedColumnName="id", unique=true)}
* )
**/
private $notifications;
Everything works fine. But I would like to add a new column to the user_notifications table, where I would like to store, if the notification is read by the given user, or not. How should I manage it in Doctrine2?
You will have to refactor your entities to introduce a new and transform your user_notifications adjacency table into an entity.
Solution
Transform you table as follows:
Then refactor your associations as follows:
User entity
...
/**
* #OneToMany(targetEntity="UserNotification", mappedBy="notification_id")
**/
private $notifications;
Notification entity
...
/**
* #OneToMany(targetEntity="UserNotification", mappedBy="user_id")
**/
private $users;
UserNotification entity
/** #Entity **/
class UserNotification {
...
/**
* #ManyToOne(targetEntity="User", inversedBy="notifications")
* #JoinColumn(name="user_id", referencedColumnName="id")
**/
private $user_id;
/**
* #ManyToOne(targetEntity="Notification", inversedBy="users")
* #JoinColumn(name="notification_id", referencedColumnName="id")
**/
private $notification_id;
/** #Column(type="boolean") */
private $read;
You'll need to create new entity with this extra column.
You can find details in this answer: https://stackoverflow.com/a/15630665/1348344

adding created timestamp to join table in doctrine2

I have the following property in my User entity to track followers and following. Basically a user can follow other user as well. I have a join column called app_user_follow_user, however I also wanted to add a timestamp of whenever someone follows another user, when did it happen. How can I specify a created timestamp via this ORM?
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="following")
*/
protected $followers;
/**
* #ORM\ManyToMany(targetEntity="User", inversedBy="followers")
* #ORM\JoinTable(name="app_user_follow_user",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="follow_user_id", referencedColumnName="id")}
* )
*/
protected $following;
Doctrine ManyToMany relationships are used when your join table has two columns. If you need to add another column you have to convert the relationship to OneToMany on both sides and ManyToOne on the joined entity.
This is entirely untested but it will hopefully give you the gist.
User Entity
/**
* #ORM\OneToMany(targetEntity="AppUserFollowUser", mappedBy="appUser")
*/
protected $followers;
/**
* #ORM\OneToMany(targetEntity="AppUserFollowUser", mappedBy="followUser")
*/
protected $following;
AppUserFollowUser Entity
/**
* #ORM\Table(name = "app_user_follow_user")
*/
class AppUserFollowUser
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="User", inversedBy="followers")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
private $appUser;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="User", inversedBy="following")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="follow_user_id", referencedColumnName="id")
* })
*/
private $followUser;
/**
* #ORM\Column(name="created_date", type="datetime", nullable=false)
*/
private $createdDate;
}
I think that you will have to create a link entity manually (entiy1 onetomany linkEntity manytoone entity2.
Because, the usual link entity are automated and should be as simple and (data less) as possible, so doctrine can take all the controle over it,
imagine you need to get the timestamp, how can you do it on an (none hard coded) entity, you will need a getter, and the annotations are not supposed to contains code.

Doctrine #UniqueEntity with ManyToOne fields?

I'm trying to create a UniqueEntity with 2 fields (both are ManyToOne fields).
The code is as follow:
/*
* #ORM\Table()
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
* #UniqueEntity(fields={"user", "connect"})
*/
class UserConnect
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var boolean $isLeader
*
* #ORM\Column(name="isLeader", type="boolean")
*/
private $isLeader;
/**
* #var date $joinedDate
*
* #ORM\Column(name="joinedDate", type="date")
*/
private $joinedDate;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="userConnects")
*
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity="Connect", inversedBy="userConnects")
*
*/
private $connect;
The goal is to ensure that I've got only one Entity that link a USER with a CONNECT.
Should I write something else in my #UniqueEntity declaration?
I understand you want to get an error only when both user and connect fields for one record are duplicated in other record in the database.
The #UniqueEntity annotation is rightly declared for your purpose (multiple column index) but only will be triggered in the form validation and doesn't affects the DDBB schema.
If you want to add the same check at database level you should use the #UniqueConstraint annotation in the Table() declaration and give a name to the new index. Something like:
/*
* #ORM\Table(uniqueConstraints={#ORM\UniqueConstraint(name="IDX_USER_CONNECT", columns={"user_id", "connect_id"})})
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
* #UniqueEntity(fields={"user", "connect"})
*/
class UserConnect
{
In the other hand, if you declare #ORM\Column(unique=true) in each attribute you will get a very different behavior, it won't be a multiple column index but you will have two independent unique columns, if you enter twice the same user_id you will get an error independently of the connect_id value, and the same will happens if you enter twice the same connect_id value.
This works:
/**
* State
*
* #ORM\Table(
* name="general.states",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="states_country_name_code_key", columns={"idcountry", "name","code"}),
* })
* #ORM\Entity(repositoryClass="Fluency\Bundle\GeneralBundle\Entity\Repository\StateRepository")
*/
class State
{.......
Taken from an entity on my system. This way affects Database schema. See where i put #\ORM\UniqueConstraint annotation. Sorry #estopero... next time i must read first the other answers.
you should add the unique declaration in your attributes annotations too.
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="userConnects")
* #ORM\Column(unique=true)
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity="Connect", inversedBy="userConnects")
* #ORM\Column(unique=true)
*/
private $connect;
See this symfony doc and this StackOverflow answer.

Categories