One entity having 2 ManyToOne relations to the same other entity - php

I'm working with Symfony5. I have 2 entities with relationships, Character and Wedding.
Each Character can have many Wedding.
Each Wedding is related to 2 different Character.
/**
* #ORM\Entity(repositoryClass=CharacterRepository::class)
*/
class Character
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=50, nullable=true)
*/
private $firstName;
/**
* #ORM\Column(type="string", length=50, nullable=true)
*/
private $lastName;
[...]
And Wedding :
/**
* #ORM\Entity(repositoryClass=WeddingRepository::class)
*/
class Wedding
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=4, nullable=true)
*/
private $startYear;
/**
* #ORM\Column(type="string", length=4, nullable=true)
*/
private $endYear;
[...]
}
I tried to set 2 different ManyToOne relations in Wedding entity (persona1 and persona2) but persona1 and persona2 had the same inversedBy="weddings", so it's not working.
I tried 2 ManyToMany relations too, but Doctrine didn't like it :
// Character
/**
* #ORM\ManyToMany(targetEntity=Wedding::class, mappedBy="persona1")
*/
private $weddings1;
/**
* #ORM\ManyToMany(targetEntity=Wedding::class, mappedBy="persona2")
*/
private $weddings2;
// Wedding
/**
* #ORM\ManyToMany(targetEntity=Character::class, inversedBy="weddings1")
*/
private $persona1;
/**
* #ORM\ManyToMany(targetEntity=Character::class, inversedBy="weddings2")
*/
private $persona2;
The mappings App\Entity\Wedding#persona2 and App\Entity\Character#weddings are inconsistent with each other.
What is the good relationship, ManyToOne or ManyToMany, since each Wedding is related to 2 Characters ? How to make it works with Doctrine ?
Thanks for all suggestion !
Ash

I would suggest to have ManyToMany relation between Wedding and Character entities if there is no such specific reason or differentiation between character 1 and character 2
class Character
{
// ...
/**
* #ORM\ManyToMany(targetEntity=Wedding::class, mappedBy="characters")
*/
private $weddings;
}
class Wedding
{
// ...
/**
* #ORM\ManyToMany(targetEntity=Character::class, inversedBy="weddings")
*/
private $characters;
}
This way you can scale it in future if you have more characters to be assigned to a wedding
If there are any strict actions that need to be performed specific to character 1 or character 2 depends on your needs, then you can use OneToMany and ManyToOne as
class Character
{
// ...
/**
* #ORM\OneToMany(targetEntity=Wedding::class, mappedBy="characterA")
*/
private $weddingsA;
/**
* #ORM\OneToMany(targetEntity=Wedding::class, mappedBy="characterB")
*/
private $weddingsB;
}
class Wedding
{
// ...
/**
* #ORM\ManyToOne(targetEntity=Character::class, inversedBy="weddingsA")
*/
private $characterA;
/**
* #ORM\ManyToOne(targetEntity=Character::class, inversedBy="weddingsB")
*/
private $characterB;
}

Related

A new entity was found through the relationship that was not configured to cascade persist operations for entity

In my project I have 2 tables Devis and DetailsDevis they are both link with a ManyToOne Mapping
Devis :
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="boolean")
*/
private $devis_admin;
/**
* #ORM\OneToOne(targetEntity="App\Entity\DetailsDevis", mappedBy="devis_id", cascade={"persist"})
*/
private $devis_id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="utilisateur_id")
* #ORM\JoinColumn(nullable=false)
*/
private $utilisateur_id;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $intitule_devis;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $periodicite;
/**
* #ORM\Column(type="blob", nullable=true)
*/
private $rappel_du_besoin;
And my DetailsDevis entity :
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $quantite;
/**
* #ORM\Column(type="decimal", precision=9, scale=2)
*/
private $prix_vente;
/**
* #ORM\Column(type="decimal", precision=5, scale=2)
*/
private $taxe_vente;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Devis", inversedBy="devis_id", cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
*/
private $devis_id;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Produit", mappedBy="detailsDevis")
*/
private $produits;
In one of my controller I want to instantiate a new devis Object, I did this :
$devis = (new Devis())
->setDevisAdmin(0)
->setUtilisateurId($this->getUser());
$this->entityManagerInterface->persist($devis);
$this->entityManagerInterface->flush();
But when I try to run the code the following error appear :
A new entity was found through the relationship
'App\Entity\Produit#detailsDevis' that was not configured to cascade
persist operations for entity:
App\Entity\DetailsDevis#000000006abb04ea000000001f58b5a5. To solve
this issue: Either explicitly call EntityManager#persist() on this
unknown entity or configure cascade persist this association in the
mapping for example #ManyToOne(..,cascade={"persist"}). If you cannot
find out which entity causes the problem implement
'App\Entity\DetailsDevis#__toString()' to get a clue.
The fact is DetailsDevis already have a cascade={"persist"} association Mapping.
The message also told me that create a __toString(), could help me to find a clue. But I don't know on what I need to return to create a this toString most of my informations on the table are decimal or relation... Did someone have an idea about what to do ?
THank you.
Change persist to merge. worked for me
`$devis = (new Devis())
->setDevisAdmin(0)
->setUtilisateurId($this->getUser());
$this->entityManagerInterface->merge($devis);
$this->entityManagerInterface->flush();`

#ORM\ManyToOne (Doctrine trying to fill object instead of int value into column)

I'm working on a form using a #ORM\ManyToOne association, but Doctrine keeps trying to parse the Airport Entity instead of the id of the Airport Entity, I've tried several annotations like #ORM\JoinColumn(name="id", referencedColumnName="id") but I can't find the right annotation to make doctrine parse just the id of the entity instead of the entity object, any help would be appreciated. Also I'm not seeking a quick and dirty fix, I'm seeking a clean and correct way to do this using the Doctrine annotations if possible.
Full Error Message:
An exception occurred while executing 'INSERT INTO flight (from, to) VALUES (?, ?)' with params [{}, {}]:
Notice: Object of class App\Entity\Airport could not be converted to int
Flight.php
/**
* #ORM\Entity(repositoryClass="App\Repository\FlightRepository")
* #ORM\Table(name="flight",
* uniqueConstraints={#ORM\UniqueConstraint(name="flight",columns={"from","to"})}
* )
*/
class Flight
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Airport", inversedBy="outbound")
* #ORM\JoinColumn(name="id")
*/
private $from;
/**
* #ORM\ManyToOne(targetEntity="Airport", inversedBy="inbound")
* #ORM\JoinColumn(name="id")
*/
private $to;
public function __toString()
{
return $this->name;
}
Airport.php
/**
* #ORM\Entity(repositoryClass="App\Repository\AirportRepository")
*/
class Airport
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="string", length=200)
*/
private $region;
/**
* #ORM\OneToMany(targetEntity="Flight", mappedBy="to")
*/
private $inbound;
/**
* #ORM\OneToMany(targetEntity="Flight", mappedBy="from")
*/
private $outbound;
I finally figured out that the issue was on the #ORM\ManyToOne() side, by chatting with Jakumi:
And that #ORM\JoinColumn() converts the entity to a int.
He also pointed out from is a reserved keyword in MySQL so I changed the column name to ap_from.
Flight.php
/**
* #ORM\Entity(repositoryClass="App\Repository\FlightRepository")
* #ORM\Table(name="flight",
* uniqueConstraints={#ORM\UniqueConstraint(name="flight",columns={"ap_from","ap_to"})}
* )
*/
class Flight
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Airport", inversedBy="outbound")
* #ORM\JoinColumn(name="ap_from", referencedColumnName="id")
*/
private $from;
/**
* #ORM\ManyToOne(targetEntity="Airport", inversedBy="inbound")
* #ORM\JoinColumn(name="ap_to", referencedColumnName="id")
*/
private $to;
/**
* #ORM\Column(type="text")
*/
private $kfm;
i don't see any use of putting the oneToMany annotation in the airport class or even the attributes inbounf and outbound just keep the from and to in your flight class then you access to any attribute in the airport throw your flight entity
your code should look like that :
Flight.php:
class Flight{/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Airport")
* #ORM\JoinColumn(name="airportFrom" , referencedColumnName="id")
*/
private $from;
/**
* #ORM\ManyToOne(targetEntity="Airport")
* #ORM\JoinColumn(name="airportTo", referencedCol)
*/
private $to;
Airport.php
class Airport{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="string", length=200)
*/
private $region;
and if you are worried about how to get the flights coming in or out from an airport a simple sql query should do it

Doctrine Associations in symfony

so I have been working with Symfony for a while but there is one thing that bothers.
It's about Doctrine Associations.
The thing is that I am trying to achieve a user friend invites and relations and there is a page that the user can see the invitations he sent and the ones that are pending.
EDIT: I made it happen using Many-To-One/One-To-Many associations. However
My question is - Are Doctrine Associations the correct way of doing that.
My User Entity
class User implements UserInterface
{
private $id;
/**
* #ORM\Column(name="first_name", type="string", length=30)
*
* #Assert\NotBlank(message="First name cannot be a blank field", groups={"register"})
* #Assert\Length(min="3", max="30", groups={"register"})
*/
/**
* #ORM\Column(type="string", length=50)
*
* #Assert\NotBlank(message="Username cannot be a blank field", groups={"register"})
* #Assert\Length(min="7", max="50", groups={"register"})
*/
private $username;
/**
* #ORM\Column(type="string", length=255)
*
* #Assert\Length(min="7", max="50", groups={"register"})
*/
private $password;
/**
* #ORM\OneToMany(targetEntity="App\Entity\UserInvitation", mappedBy="inviterId", orphanRemoval=true)
*/
private $userInvitations;
/**
* #ORM\OneToMany(targetEntity="App\Entity\UserInvitation", mappedBy="invitedId", orphanRemoval=true)
*/
private $pendingUserInvitations;
//getters and setters
My UserInvitation Entity
class UserInvitation
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="userInvitations")
* #ORM\JoinColumn(name="inviter_id", nullable=false)
*/
private $inviterId;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="pendingUserInvitations")
* #ORM\JoinColumn(name="invited_id", nullable=false)
*/
private $invitedId;
/**
* #ORM\Column(type="boolean")
*/
private $status;
This is my database.
The relationships is the right way to do it although on the entity I would use the following:
class UserInvitation
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="userInvitations")
* #ORM\JoinColumn(name="inviter_id", nullable=false)
*/
private $inviter;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="pendingUserInvitations")
* #ORM\JoinColumn(name="invited_id", nullable=false)
*/
private $invitee;
/**
* #ORM\Column(type="boolean")
*/
private $status;
Then you would getInviter() or setInviter(). Basically think that you are saving the related object to the entity and not the related field

symfony2 combine primary key and relation

I'm trying to get a legacy database into the doctrine mappings.
All the tables have a combined primary key. One ID and one "optios id".
The problem is that Optios ID always has to be set but the OneToOne relation with the same columns causes the column "Optios ID" to be set to null. I'm not sure what I'm doing wrong or is there a way around it?
PS: The 'Pack' relation is optional.
<?php
namespace CalendarBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="CalendarBundle\Repository\CategoryRepository")
* #ORM\Table(name="Categories")
*/
class Category
{
/**
* #ORM\Id
* #ORM\Column(type="integer", name="Category_id")
*/
private $id;
/**
* #ORM\Column(type="integer", name="Optios_id")
* #ORM\Id
*/
private $optiosId;
/**
* #ORM\Column(type="string", name="Name")
*/
private $name;
/**
* #ORM\Column(type="boolean", name="AvailableOnline")
*/
private $online;
/**
* #ORM\Column(type="integer", name="SequenceNumber", nullable=true)
*/
private $order;
/**
* #ORM\Column(type="integer", name="Parent_id")
*/
private $parentId;
/**
* One Category has Many Packs.
*
* #var Pack
*
* #ORM\OneToOne(targetEntity="Pack", inversedBy="category")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="Pack_id", referencedColumnName="Pack_id"),
* #ORM\JoinColumn(name="Optios_id", referencedColumnName="Optios_id"),
* )
*/
private $pack;
/**
* #ORM\Column(type="boolean", name="Deleted")
*/
private $deleted;

Relationship between two intermediate entities in Symfony2

I have five entities :
ProductA, ProductB, User, UserProductA and UserProductB. The two last ones are "intermediate" entites which contain the attributes of relationships between ProductA, ProductB and User.
I would like to make a ManyToOne relationship between UserProductA and UserProductB but it doesn't work. When I try to update the database, I get this error : Single id is not allowed on composite primary key in entity.
UserProductA (without the relationship) :
/**
* #ORM\Entity(repositoryClass="Gam\UserBundle\Entity\UserProductARepository")
*/
class UserProductA
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Gam\FicheBundle\Entity\ProductA")
*/
private $producta;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Gam\UserBundle\Entity\User")
*/
private $user;
/**
* #ORM\Column(type="string", length=1, nullable=true)
*/
private $attribute;
etc...
}
UserProductB (without the relationship) :
/**
* #ORM\Entity(repositoryClass="Gam\UserBundle\Entity\UserProductBRepository")
*/
class UserProductB
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Gam\FicheBundle\Entity\ProductB")
*/
private $productb;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Gam\UserBundle\Entity\User")
*/
private $user;
/**
* #ORM\Column(type="string", length=1, nullable=true)
*/
private $attribute;
etc...
}
How can I make it work ?

Categories