PHP

Tutorials and guides on PHP

Symfony2 Entity Dependency

Written by: Peter Fisher on July 31, 2012
Tagged under: , ,
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

I recently asked a question on stackoverflow  on how to target a external Doctrine entity  from a separate bundle. Simply put, how do we handle entity dependencies across bundles. In this post I would like to discuss my thought process in separating the entities and give a more detailed briefing into the solution that was kindly added by Florent.

In my example I have two bundles, a PropertyBundle and a UserBundle. Each bundle has an entity, the UserBundle has a User entity  and the  PropertyBundle has a Property entity.   The property entity has a ManyToMany relationship with  a User entity which means many users belong to many properties and visa versa. As both entities are housed in their own bundle, I wasn’t sure how to create the target across the two name spaces.

I started off with the User entity in the UserBundle:

namespace Pfwd\UserBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="user")
 */
class User implements UserInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     * 
     * @var integer $id
     */
    protected $id;

   // ...

Then the Property entity inside the PropertyBundle:

namespace Pfwd\AdminBundle\PropertyBundle\Entity;

use Pfwd\UserBundle\Entity\User as User;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="property")
 */
class Property {

//...
/**
 * @ORM\ManyToMany(targetEntity="User")
 * @ORM\JoinTable(name="property_user",
 *     joinColumns={@ORM\JoinColumn(name="property_id", referencedColumnName="id")},
 *     inverseJoinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}
 * )
 *
 * @var ArrayCollection $salesAgents
 */
  protected $salesAgents;

//..

As you can see I included the line:

use Pfwd\UserBundle\Entity\User as User;

in the hope that targetEntity would be picked up like so:

@ORM\ManyToMany(targetEntity="User")

However this was not the case and a error was thrown each time I tried to update the database schema.

The fix was to call the targetEntity directly in the annotation  like so:

@ORM\ManyToMany(targetEntity="Pfwd\UserBundle\Entity\User")

This makes sense as the Doctrine annotations are not aware of what name spaces are being used in the class.

Why structure the bundles like this?

Well, I have other projects with different needs and requirements. All secure systems will require the UserBundle so a user can log into an interface and do user related stuff.  The PropertyBundle is tailored for a property site. The nature of the bundle is around addresses and properties etc… Multiple properties can be managed by multiple sales agents who are users to the system. However this is where the link between the two bundles end.

By keeping the name spaces separate I have decoupled any user logic from the property logic, making both bundles reusable and more maintainable.  I could further extend the User entity to target a Person entity in a OneToOne relationship as a user may not always be a person and the fields ‘lastLogin’ or ‘IPAddress’ are not related to a person rather a login attempt. The downside to all of this is that I am introducing  dependencies amongst bundles but this can be simply managed by Symfony. Of course you can have multiple entities within a bundle, but you should always  keep the nature of the entity in-line with nature of the bundle.

profile for pfwd at Stack Overflow, Q&A for professional and enthusiast programmers

EDIT: I’ve updated the annotation in the Property entity to reference the correct table (property_user). This is different to the stackoverflow example

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

Peter Fisher is a web developer working in Gloucester UK. Founder of the digital agency Websomatic, author of this blog and the HowToCodeWell Youtube channel. Peter has over ten years of web development experience under his belt

Read all about Peter Fisher

Leave a Reply

Your email address will not be published. Required fields are marked *