Doctrine - ORM - Fetching all data using entityManager with associaction - php

I have two entities user1 and skills, where one user will have many skills.
/** #Entity **/
class user1 {
/** #Id #Column(type="integer") #GeneratedValue **/
public $id;
/** #Column(type="string") **/
public $name;
/**
*
* #OneToMany(targetEntity="skills", mappedBy="uid")
*/
public $skillset;
}
/** #Entity **/
class skills {
/** #Id #Column(type="integer") #GeneratedValue **/
public $id;
/** #Column(type="string") **/
public $skill;
/**
* #ManyToOne(targetEntity="user1", inversedBy="skillset")
**/
public $uid;
}
But I want to fetch all the records using entityManager and getrepository like
$usr= $entityManager->getRepository("user1")->findAll();
But it gives me data from table 'user1' only. And I am not able to fetch the data from 'skills' which is associated to particular user.
'uid' is the foreign key in 'skills' table of 'id' in 'user1' table.

I think you may prefer a ManyToMany relationship, because many users will have many skills.
Then you don't have to refer fields as IDs - and ORM's purpose is to hide the relational structure under the object relationship: your $uid field should be called $user.
Such said, your syntax is correct - are you sure your database schema is in sync with the entities? Have you got proper data in it? If you var_dump a single user, what you get?

Related

Doctrine ManyToOne relationship - auto-remove on "set"

I'm working with relationships in Doctrine (using Symfony 5).
What I have is these 2 relations:
User
Availability
User has an ID and has Many Availabilities.
So Entity User has
/**
* #ORM\OneToMany(targetEntity="UserAvailability", mappedBy="user")
*/
private $availability;
and the reverse on Entity Availability.
Availability is a relation with:
id, user_id, day_name, start_time and end_time, that simple.
What I already achieved with ManyToMany and I want to achieve in this case too is:
I need to receive the entire set of availabilities for a User from the client and use it to update the availabilities of my User, so I defined a setAvailability method which receives a Collection of Availability entities and simply does
$this->availabilities = $availabilities.
This works when I add new availabilities but the ones that are on the DB and not in the collection are not dropped when I persist the entity.
The same method works flawlessly with ManyToMany Relationship.
What am I missing?
*** UPDATE **
public function setAvailability($availability): self
{
$this->availability = $availability;
return $this;
}
this same code works when removing relations in ManyToMany relationship but not in ManyToOne, the attribute "availability" is correctly set, but when using persist/flush the availability which was removed is not removed on the DB.
Thanks
Try to set the attributes as in the example from the doctrine documentation below :
<?php
use Doctrine\Common\Collections\ArrayCollection;
/** #Entity */
class User
{
// ...
/**
* One user has many availabilities. This is the inverse side.
* #OneToMany(targetEntity="Availability", mappedBy="user")
*/
private $availabilities;
// ...
public function __construct() {
$this->availabilities = new ArrayCollection();
}
}
/** #Entity */
class Availability
{
// ...
/**
* Many availabilities have one user. This is the owning side.
* #ManyToOne(targetEntity="User", inversedBy="availabilities")
* #JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
// ...
}
the attribute mappedBy and inversedBy are necessary for relations

How to show relational columns in grid using APYDataGridBundle?

I use APYDataGridBundle for generating a data table.
I have Person entity with a relation (1 gym can have more people):
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Gym", inversedBy="persons")
*/
private $gym;
I generate a grid with a list of people in controller:
public function indexAction(Grid $grid)
{
// Creates a simple grid based on your entity (ORM)
$source = new Entity(Person::class);
$grid->setSource($source);
return $grid->getGridResponse('Person/index.html.twig');
It shows me the grid with all non-relational columns, but the gym column not, because of the relation.
I can't find the solution in doc: https://github.com/APY/APYDataGridBundle/blob/master/Resources/doc/summary.md
Can you help me?
In Person entity:
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Gym", inversedBy="persons")
*
* #GRID\Column(field="gym.id", title="Gym ID")
* #GRID\Column(field="gym.title", title="Gym Title")
*/
private $gym;

Symfony2. Relation between multiple databases in Entity

I have 2 doctrine entities:
class User extends BaseUser
{
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Account", mappedBy="user")
*/
protected $accounts;
and:
class Account
{
/**
* #var \UserBundle\Entity\User
* #ORM\ManyToOne(targetEntity="\UserBundle\Entity\User", inversedBy="accounts")
* #ORM\JoinColumn(name="a_person_obj_id", referencedColumnName="obj_id")
*/
protected $user;
The problem is that the data for Account entity storeted in different database that entity User.
When I getting User entity:
$userRepository = $this->getDoctrine()->getRepository('UserBundle:User', 'db1');
$user = $userRepository->find($user);
and start iterating by $user->getAccounts() I getting exception:
SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "account" does not exist
and this absolutely correct, because Account stored in "db2" and I need to user different entity manager for this data.
What's the best practices to make relation between many databases for entity?
P.S. I used to postgreSQL database.

Doctrine's Many-To-Many Self-Referencing and reciprocity

By default, self-referencing ManyToMany relationships under Doctrine involve an owning side and an inverse side, as explained in the documentation.
Is there a way to implement a reciprocal association whithout difference between both sides?
Following the example in the docs:
<?php
/** #Entity **/
class User
{
// ...
/**
* #ManyToMany(targetEntity="User")
**/
private $friends;
public function __construct() {
$this->friends = new \Doctrine\Common\Collections\ArrayCollection();
}
// ...
}
So, adding entity1 to entity2s friends implies that entity2 will be in entity1s friends.
There are a number of ways to solve this problem, all depending on what the requirements for the "friends" relation are.
Unidirectional
A simple approach would be to use a unidirectional ManyToMany association, and treat it as if it where a bidirectional one (keeping both sides in sync):
/**
* #Entity
*/
class User
{
/**
* #Id
* #Column(type="integer")
*/
private $id;
/**
* #ManyToMany(targetEntity="User")
* #JoinTable(name="friends",
* joinColumns={#JoinColumn(name="user_a_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="user_b_id", referencedColumnName="id")}
* )
* #var \Doctrine\Common\Collections\ArrayCollection
*/
private $friends;
/**
* Constructor.
*/
public function __construct()
{
$this->friends = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #return array
*/
public function getFriends()
{
return $this->friends->toArray();
}
/**
* #param User $user
* #return void
*/
public function addFriend(User $user)
{
if (!$this->friends->contains($user)) {
$this->friends->add($user);
$user->addFriend($this);
}
}
/**
* #param User $user
* #return void
*/
public function removeFriend(User $user)
{
if ($this->friends->contains($user)) {
$this->friends->removeElement($user);
$user->removeFriend($this);
}
}
// ...
}
When you call $userA->addFriend($userB), $userB will be added to the friends-collection in $userA, and $userA will be added to the friends-collection in $userB.
It will also result in 2 records added to the "friends" table (1,2 and 2,1). While this can be seen as duplicate data, it will simplify your code a lot. For example when you need to find all friends of $userA, you can simply do:
SELECT u FROM User u JOIN u.friends f WHERE f.id = :userId
No need to check 2 different properties as you would with a bidirectional association.
Bidirectional
When using a bidirectional association the User entity will have 2 properties, $myFriends and $friendsWithMe for example. You can keep them in sync the same way as described above.
The main difference is that on a database level you'll only have one record representing the relationship (either 1,2 or 2,1). This makes "find all friends" queries a bit more complex because you'll have to check both properties.
You could of course still use 2 records in the database by making sure addFriend() will update both $myFriends and $friendsWithMe (and keep the other side in sync). This will add some complexity in your entities, but queries become a little less complex.
OneToMany / ManyToOne
If you need a system where a user can add a friend, but that friend has to confirm that they are indeed friends, you'll need to store that confirmation in the join-table. You then no longer have a ManyToMany association, but something like User <- OneToMany -> Friendship <- ManyToOne -> User.
You can read my blog-posts on this subject:
Doctrine 2: How to handle join tables with extra columns
More on one-to-many/many-to-one associations in Doctrine 2

OneToMany Relation with reference on a third table?

I got two entities with a simple OneToMany relation and anything works as expected.
The user entity:
class User {
/**
* #ORM\OneToMany(targetEntity="Vita", mappedBy="owner")
*/
}
and the vita entity:
class Vita {
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="vitas")
*/
}
So far, so good. But now I changed the vita entity and added the meta entity with a OneToOne relation. This entity knows the owner and other stuff, but the vita does not have longer a owner property.
What I am looking for is the oppotunity to use the third table as reference. Is there a common doctrine way? Something like that?
class User {
/**
* #ORM\OneToMany(targetEntity="Vita", mappedBy="meta.owner")
*/
}
EDIT:
User
- id
- username
- password
Vita
- id
- meta_id
- [other fields]
Meta
- id
- owner_id (User)
- modifier_id (User)
- [other fields]
One User has many Vita
One Vita has one Meta
First the owner_id was a property of vita and now it moved into meta.
According to the relationship schema, it should look like this:
class User {
/**
* #ORM\OneToMany(targetEntity="Meta", mappedBy="owner")
*/
protected $metasOwned;
/**
* #ORM\OneToMany(targetEntity="Meta", mappedBy="modifier")
*/
protected $metasModified;
}
class Vita {
/**
* #ORM\OneToOne(targetEntity="Meta", inversedBy="vita")
*/
protected $meta;
}
class Meta {
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="metasOwned")
*/
protected $owner;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="metasModified")
*/
protected $modifier;
/**
* #ORM\OneToOne(targetEntity="Vita", mappedBy="meta")
*/
protected $vita;
}
Notice that variable names correlate with the inverse-side of the relationships.
Then you just run the command
php app/console doctrine:generate:entities Your/AwesomeBundle/Entity
and it will create getters & setters for you and you will be all set.
Your/AwesomeBundle/Entity: the real path is or could be src/Your/AwesomeBundle/Entity.

Categories