(DOCTRINE) mappedBy and inversedBy and targetEntity annotations - php

What values goes inside this inversedBy annotation as well as the mappedBy annotation? Also what is targetEntity and referencedColumnName?
Here is an example of my comment entity. As you can see, in my tutorials it says to write the string comments inside the inversedBy attribute and \Application\Entity\Post inside the targetREntity attribute.
/**
* This class represents a comment related to a blog post.
* #ORM\Entity
* #ORM\Table(name="comment")
*/
class Comment
{
/**
* #ORM\ManyToOne(targetEntity="\Application\Entity\Post", inversedBy="comments")
* #ORM\JoinColumn(name="post_id", referencedColumnName="id")
*/
protected $post;
}
For this one, it says comments. What exactly is this comments string referring to?
I dont know what comments means. Is this a mapping to a table, or the ORM name of the class at the top, or something else.
Also,
Here is an example of where mappedBy is used:
/**
* #ORM\Entity
* #ORM\Table(name="post")
*/
class Post
{
// Post status constants.
const STATUS_DRAFT = 1; // Draft.
const STATUS_PUBLISHED = 2; // Published.
/**
* #ORM\OneToMany(targetEntity="\Application\Entity\Comment", mappedBy="post")
* #ORM\JoinColumn(name="id", referencedColumnName="post_id")
*/
protected $comments;
I started reading about owning sides and inverse sides click here but it was extremely difficult to understand.
Any details on anything here would be great.
Any help would be great.

I'm not doctrine expect but I used to work with it for some time so I'll try to explain what I know so far.
InversedBy refers to $comments property (field) in Post entity and vice versa.
The inverse side has to use the mappedBy attribute of the OneToOne,
OneToMany, or ManyToMany mapping declaration. The mappedBy attribute
contains the name of the association-field on the owning side.
The owning side has to use the inversedBy attribute of the OneToOne,
ManyToOne, or ManyToMany mapping declaration. The inversedBy attribute
contains the name of the association-field on the inverse-side.
When you use #ORM\ManyToOne annotation you are creating n:1 relationship. There are three types of mapping:
bidirectional - Post with access to Comment and vice versa
unidirectional - Post with $comments field full of Comment entities but you won't have ability to access Post from Comment, because it is not mapped back
self-referencing - Category with with self-reference to parent Category which is entity of same type
TargetEntity tells to which entity you are creating relationship. Imagine foreign key. When you create foreign key you need to specify referencing table.
ReferencedColumnName tells to which column foreign key should be created.
Doctrine is not magic. It is just Object Relation Mapping. Think about it like when you used SQL to create relations. A lot of things are almost same.

Related

Enter entity property from the inversed side in one to one relation

Let's assume i have an one-to-one relation with one entity person
class Person
{
...
/**
* #var Player
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Player", inversedBy="person")
*/
private $player;
...
}
and one entity Player
class Player
{
...
/**
* #var Person
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Person", mappedBy="player")
*/
private $person;
...
}
Now the person side is holding the foreign key for the person.
Every try to access something from the inversed side is failing, for example
$em->getRepository('AppBundle:Player')->findByPerson();
ends up in
[Doctrine\ORM\ORMException]
You cannot search for the association field
'AppBundle\Entity\Player#person', because it is the inverse side of
an association. Find methods only work on owning side associations.
Doing the same to the owning side (find player for the person), everything is fine.
I cant figure out: How can i access entities from both sides?
I need that, because i need to know, which player hasn't already persons assigned and vice versa. I thought, doctrine is loading the related entities ... for this case plain sql seems the easier solution for that? Or have i really to deal with dql and joins?
In your class Player, can you try with this :
class Player
{
...
/**
* #var Person
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Person", mappedBy="player")
* #ORM\JoinColumn(name="person_id", referencedColumnName="id")
*/
private $person;
...
}
Here is the doctrine doc: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-one-bidirectional

Symfony&Doctrine2: Value of `mappedBy` annotation?

I am learning Symfony 3 with Doctrine 2.
When I have OneToMany relationship in Doctrine entity, what exactly I have to put into mappedBy annotation?
Is it the table name of current entity?
Or is it the entity shortcut?
Or is it the actual class name?
Imagine this simple example:
<?php
namespace AppBundle\Entity;
/**
* #ORM\Entity
* #ORM\Table(name="blog_category")
*/
class Category
{
// ...
/**
* #ORM\OneToMany(targetEntity="Article", mappedBy="category")
*/
private $articles;
// ...
}
Why is the "category" correct value for mappedBy? Why isn't it "blog_category" or "Category" (uppercase "C")? Or "AppBundle:Category"?
Now I figured it out. It is the name of related's entity class variable :-)
To give a complement, almost everything you could do in doctrine (could surely be applied for any other ORM/ODM), in almost every contexts (QueryBuilder, findBy methods, ...) you'll use property names rather than column names.
The reason is quite simple, an ORM deals with objects and their properties, abstracting the real tables and their columns, no matter of the database engine or anything else.

What is the owning side and inverse side in the doctrine 2 doc example

On this page of association mapping, there's an example in the manytomany section. But I don't understand which entity (group or user) is the owning side.
http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html#many-to-many-bidirectional
I've put the code here too
<?php
/** #Entity */
class User
{
// ...
/**
* #ManyToMany(targetEntity="Group", inversedBy="users")
* #JoinTable(name="users_groups")
*/
private $groups;
public function __construct() {
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
/** #Entity */
class Group
{
// ...
/**
* #ManyToMany(targetEntity="User", mappedBy="groups")
*/
private $users;
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
Do I read this annotation like this:
User is mappedBy groups so group is the entity that does the connection management, thus the owning side?
Also, I've read this in the docs:
For ManyToMany bidirectional relationships either side may be the owning side (the side that defines the #JoinTable and/or does not make use of the mappedBy attribute, thus using a default join table).
This lets me think that User would be the owning side as the JoinTable annotation is defined in that entity.
But I don't understand which entity (group or user) is the owning side
The User entity is the owner. You have the relation of groups in User:
/**
* #ManyToMany(targetEntity="Group", inversedBy="users")
* #JoinTable(name="users_groups")
*/
private $groups;
Look above, $groups var contains the all groups associated to this user, but If you notice the property definition, $groups var has the same name of mappedBy value (mappedBy="groups"), as you did:
/**
* #ManyToMany(targetEntity="User", mappedBy="groups")
*/
private $users;
What does mappedBy mean?
This option specifies the property name on the targetEntity that is the owning side of this relation.
Taken from the docs:
In a one-to-one relation the entity holding the foreign key of the
related entity on its own database table is always the owning side of
the relation.
In a many-to-one relation the Many-side is the owning side by default,
because it holds the foreign key. The OneToMany side of a relation is
inverse by default, since the foreign key is saved on the Many side. A
OneToMany relation can only be the owning side, if its implemented
using a ManyToMany relation with join table and restricting the one
side to allow only UNIQUE values per database constraint.
Now, I understand ManyToMany can be confusing some times.
For Many-To-Many associations you can choose which entity is the owning and which the inverse side. There is a very simple semantic rule to decide which side is more suitable to be the owning side from a developers perspective. You only have to ask yourself, which entity is responsible for the connection management and pick that as the owning side.
Take an example of two entities Article and Tag. Whenever you want to connect an Article to a Tag and vice-versa, it is mostly the Article that is responsible for this relation. Whenever you add a new article, you want to connect it with existing or new tags. Your createArticle form will probably support this notion and allow to specify the tags directly. This is why you should pick the Article as owning side, as it makes the code more understandable:
<?php
class Article
{
private $tags;
public function addTag(Tag $tag)
{
$tag->addArticle($this); // synchronously updating inverse side
$this->tags[] = $tag;
}
}
class Tag
{
private $articles;
public function addArticle(Article $article)
{
$this->articles[] = $article;
}
}
This allows to group the tag adding on the Article side of the association:
<?php
$article = new Article();
$article->addTag($tagA);
$article->addTag($tagB);
So, in short, whatever makes more sense to you. You choose the owning and the inverse side of the relationship. :)
Source: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html

What is the difference between inversedBy and mappedBy?

I am developing my application using Zend Framework 2 and Doctrine 2.
While writting annotations, I am unable to understand the difference between mappedBy and inversedBy.
When should I use mappedBy?
When should I use inversedBy?
When should I use neither?
Here is an example:
/**
*
* #ORM\OneToOne(targetEntity="\custMod\Entity\Person", mappedBy="customer")
* #ORM\JoinColumn(name="personID", referencedColumnName="id")
*/
protected $person;
/**
*
* #ORM\OneToOne(targetEntity="\Auth\Entity\User")
* #ORM\JoinColumn(name="userID", referencedColumnName="id")
*/
protected $user;
/**
*
* #ORM\ManyToOne (targetEntity="\custMod\Entity\Company", inversedBy="customer")
* #ORM\JoinColumn (name="companyID", referencedColumnName="id")
*/
protected $company;
I did a quick search and found the following, but I am still confused:
example 1
example 2
example 3
mappedBy has to be specified on the inversed side of a (bidirectional) association
inversedBy has to be specified on the owning side of a (bidirectional) association
from doctrine documentation:
ManyToOne is always the owning side of a bidirectional assocation.
OneToMany is always the inverse side of a bidirectional assocation.
The owning side of a OneToOne assocation is the entity with the table containing the foreign key.
See https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html
The answers above were not sufficient for me to understand what was going on, so after delving into it more I think I have a way of explaining it that will make sense for people who struggled like I did to understand.
inversedBy and mappedBy are used by the INTERNAL DOCTRINE engine to reduce the number of SQL queries it has to do to get the information you need. To be clear if you don't add inversedBy or mappedBy your code will still work but will not be optimized.
So for example, look at the classes below:
class Task
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="task", type="string", length=255)
*/
private $task;
/**
* #var \DateTime
*
* #ORM\Column(name="dueDate", type="datetime")
*/
private $dueDate;
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="tasks", cascade={"persist"})
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
}
class Category
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="Task", mappedBy="category")
*/
protected $tasks;
}
These classes if you were to run the command to generate the schema (for example, bin/console doctrine:schema:update --force --dump-sql) you will notice that the Category table does not have a column on it for tasks. (this is because it does not have a column annotation on it)
The important thing to understand here is that the variable tasks is only there so the internal doctrine engine can use the reference above it which says its mappedBy Category. Now... don't be confused here like I was... Category is NOT referring TO THE CLASS NAME, its referring to the property on the Task class called 'protected $category'.
Like wise, on the Tasks class the property $category mentions it is inversedBy="tasks", notice this is plural, this is NOT THE PLURAL OF THE CLASS NAME, but just because the property is called 'protected $tasks' in the Category class.
Once you understand this it becomes very easy to understand what inversedBy and mappedBy are doing and how to use them in this situation.
The side that is referencing the foreign key like 'tasks' in my example always gets the inversedBy attribute because it needs to know what class (via the targetEntity command) and what variable (inversedBy=) on that class to 'work backwards' so to speak and get the category information from. An easy way to remember this, is the class that would have the foreignkey_id is the one that needs to have inversedBy.
Where as with category, and its $tasks property (which is not on the table remember, just only part of the class for optimization purposes) is MappedBy 'tasks', this creates the relationship officially between the two entities so that doctrine can now safely use JOIN SQL statements instead of two separate SELECT statements. Without mappedBy, the doctrine engine would not know from the JOIN statement it will create what variable in the class 'Task' to put the category information.
Hope this explains it a bit better.
In bidirectional relationship has both an owning side and an inverse side
mappedBy : put into The inverse side of a bidirectional relationship To refer to the field in the owning side of entity
inversedBy : put into The owning side of a bidirectional relationship To refer to the field on the inverse side of entity
AND
mappedBy attribute used with the OneToOne, OneToMany, or ManyToMany mapping declaration.
inversedBy attribute used with the OneToOne, ManyToOne, or ManyToMany mapping declaration.
Notice :
The owning side of a bidirectional relationship the side that contains the foreign key.
there two reference about inversedBy and mappedBy into Doctrine Documentation :
First Link,Second Link
5.9.1. Owning and Inverse Side
For Many-To-Many associations you can chose which entity is the owning and which the inverse side. There is a very simple semantic rule to decide which side is more suitable to be the owning side from a developers perspective. You only have to ask yourself, which entity is responsible for the connection management and pick that as the owning side.
Take an example of two entities Article and Tag. Whenever you want to connect an Article to a Tag and vice-versa, it is mostly the Article that is responsible for this relation. Whenever you add a new article, you want to connect it with existing or new tags. Your create Article form will probably support this notion and allow to specify the tags directly. This is why you should pick the Article as owning side, as it makes the code more understandable:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html

Associations with Doctrine 2

I'm trying make an entity with doctrine that has three associations with other entities
So an Item is associated with:
Must be associated with One Rssfeed, which it originates from
Can be associated with One or more Locations
Can be associated with one or more Tags
Here is my attempt:
class Item{
/**
* #ManyToOne(targetEntity="Rssfeed")
*/
protected $rssfeed;
/**
*
* #ManyToMany(targetEntity="Location")
*/
protected $locations;
/**
*
* #ManyToMany(targetEntity="Tag")
*/
protected $tags;
}
Now
If an Rssfeed is removed, associated items must be removed too
If an item is removed, Rssfeeds, and Locations, and Tags attached to that item should be detached
If a Location, or Tag is removed, the associated items should just be detached, because they are optional associations.
How should I change my code to accomplish that?
For each association in your Item entity, add onDelete="SET NULL" to the #JoinColumn annotation. Inside your location and tag entities, find the JoinColumn annotations and add onDelete="SET NULL" for the association with "Item". Under the RssFeed entity, find each #JoinColumn annotation and add onDelete="SET NULL".
Note that you can also use Doctrine cascade operations to achieve this (i.e. cascade={"remove"}, etc; however, it will likely be significantly slower as the operating is not performed at the RDBMS level.
U have to add #JoinColumn with onDelete="CASCADE" for $rssfeed and onDelete="SET NULL" for foreign keys in Location and Tag entities.
/**
* #ManyToOne(targetEntity="Rssfeed")
* #JoinColumn(name="rssfeed_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $rssfeed;

Categories