Symfony2 - entity fraction between links with different relationships
How do you exchange an entity between multiple packages with different relationships?
For example, both ZooAnimalBundle and FarmAnimalBundle require a User Entity. The third Bundle has an AccountUserBundle with a Custom Object.
In both Zoo and Farm AnimalBundles, I create a User Entity like this:
use Account\UserBundle\Entity\User as BaseUser;
class User extends BaseUser
{
}
Then I have a hospital facility in the Zoo:
class Hospital {
/**
* @ORM\ManyToMany(targetEntity="Zoo\AnaimalBundle\Entity\User")
* @ORM\JoinTable(name="users_zoo_animals")
*/
protected $users;
And the facility object on the farm:
class Room {
/**
* @ORM\ManyToMany(targetEntity="Farm\AnaimalBundle\Entity\User")
* @ORM\JoinTable(name="users_farm_animals")
*/
protected $users;
Everything works so far in that I can call Zoo.Room-> getUsers () or Farm.Hospital-> getUsers ()
However, the problem is that I am not sure how to set up the feedback in my respective custom objects.
If, for example, I update the Entity Entity FarmAnimal and run doctrine: generate: entities
/**
* @ORM\Entity
*/
class User extends BaseUser
{
/**
* @ORM\ManyToMany(targetEntity="Room", mappedBy="users", cascade={"persist"})
*/
protected $rooms;
}
It will copy the protected $ properties from BaseUser and create all set and get methods that are not what I want. What is the correct way to set up this relationship?
Update
If you don't configure feedback how you select all users where hospital.id = 1
$qb = $this->getEntityManager()->createQueryBuilder()
->select(
'u'
)
->from('Account\UserBundle\Entity\User','u')
->leftJoin('u.hospitals', 'h')
->andWhere('h.id = :hospital_id')
->setParameter('hospital_id',$hospital_id);
This gives an error:
Class Account\UserBundle\Entity\User has no association named hospitals
I know I could select from the hospital and join a user because this relationship exists, but I need to select users because I am using them with Doctrine \ ORM \ Tools \ Pagination \ Paginator
The request will be
$qb = $this->createQueryBuilder('a')
->select(
'h', 'u'
)
->leftJoin('h.users', 'u')
The problem with this is that Paginator only sees one result because users are attached to it.
source to share
You can define abstract dependent entities and implement them with other packages.
First, each of the packages that depend on a custom object must define a user interface. For example:
namespace Foo\BarBundle\Entity;
interface UserInterface
{
public function getId();
public function getEmail();
// other getters
}
Then, in each user-specific object, define a relationship, for example:
namespace Foo\BarBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity
*/
class Something
{
/**
* @ORM\ManyToOne(targetEntity="UserInterface")
* @Assert\NotNull
*/
protected $User;
// add other fields as required
}
Now you need to register the User object as an implementation of UserInterfaces:
namespace Foo\UserBundle\Entity;
use Foo\BarBundle\Entity\UserInterface as BarUserInterface;
use Foo\FoobarBundle\Entity\UserInterface as FoobarUserInterface;
/**
* @ORM\Entity
*/
class User implements BarUserInterface, FoobarUserInterface
{
// implement the demanded methods
}
Then add the following to app/config/config.yml
:
doctrine:
orm:
resolve_target_entities:
Foo\BarBundle\Entity\UserInterface: Foo\UserBundle\Entity\User
Foo\FooarBundle\Entity\UserInterface: Foo\UserBundle\Entity\User
(Heads up: there will usually be a doctrine.orm
node that you will need to extend.)
This is not an ideal solution because you cannot tell which fields the custom objects should have. On the other hand, this is strictly OOP, since you don't need to know about the internals of the implementation User
- you just need to return the correct values.
source to share
Creating multiple account definitions is not the right way to do it unless you want to create 3 separate custom tables (even then, it's best not to do it that way).
Indeed, you want your other objects to map to your custom object bundled with your account.
those.
class Hospital {
/**
* @ORM\ManyToMany(targetEntity="Zoo\AccountBundle\Entity\User")
*/
protected $users;
Now there is no need to create a reverse relationship. In fact, this is bad practice since you have a bi-directional dependency. Users don't know about hospitals, but the hospital knows about it. Any package can now render a user object and reuse it.
source to share