I am a beginner in Symfony.
I have a strange problem in my form.
I have 2 entities : Proposal_Lsi and Lsi_Beams. One proposal can have multiple beams, but a beam can only have one proposal. I figured I should use a OneToMany/ManyToOne relation, and that my owning side is the beam one, and inverse side is proposal.
I followed the official guide at https://symfony.com/doc/3.1/form/form_collections.html about Form Collections.
Everything renders just fine, I can submit a new proposal with multiple beams, and all is correctly stored in the database.
The problem occurs whenever I try to add new beams to my proposal : the systems overwrites (update query) existing beams (starting by the first one in the database) instead of adding new ones (insert query).
What am I missing ?
Here's some of my code, if that can help.
Proposal Class:
class Proposal_lsi{
/**
* #ORM\OneToOne(targetEntity="Emir2Bundle\Entity\Proposal", inversedBy="proposal_lsi")
* #ORM\JoinColumn(name="proposal", referencedColumnName="id")
* #ORM\Id
*/
private $proposal;
/**
* #ORM\OneToMany(targetEntity="Emir2Bundle\Entity\Lsi_beams", mappedBy="proposal_lsi")
*/
private $lsi_beams;
...
/**
* Add lsiBeam
*
* #param \Emir2Bundle\Entity\Lsi_beams $lsiBeam
* #return Proposal_lsi
*/
public function addLsiBeam(\Emir2Bundle\Entity\Lsi_beams $lsiBeam)
{
$lsiBeam->setProposalLsi($this);
$this->lsi_beams[] = $lsiBeam;
return $this;
}
}
Beams Class:
class Lsi_beams{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Emir2Bundle\Entity\Proposal_lsi", inversedBy="lsi_beams", cascade={"persist"})
* #ORM\JoinColumn(name="proposal_lsi", referencedColumnName="proposal", nullable=false)
*/
private $proposal_lsi;
...
}
And the form in the controller :
$form = $this->createFormBuilder($proposallsi)
->setAction($this->generateUrl('lsi_submission', array('id' => $id)))
->setMethod('POST')
->add('lsi_beams', CollectionType::class, array(
'entry_type' => LsiBeamsType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false
)
)
...
What am I doing wrong ? Let me know if you need more code.
Thanks for any reply !
Notes:
use Doctrine ArrayCollection to better keep track of collections
put cascade={"persist"} at the inverse side of association (where you have mappedBy)
Keep entity names singular (e.g. Lsi_beam instead of Lsi_beams)
Keep your naming strategy clear and strait. Don't use undescores in your class & property names (e.g. use $lsiBeams instead of $lsi_beams)
ProposalLsi
use Doctrine\Common\Collections\ArrayCollection;
class ProposalLsi
{
/**
* #ORM\OneToMany(targetEntity="LsiBeam", mappedBy="proposalLsi", cascade={"persist"})
*/
private $lsiBeams;
public function __construct()
{
$this->lsiBeams = new ArrayCollection();
}
public function addLsiBeam(LsiBeams $lsiBeam)
{
if ($this->lsiBeams->contains($lsiBeam)) {
return;
} else {
$lsiBeam->setProposalLsi($this);
$this->lsiBeams->add($lsiBeam);
}
return $this;
}
public function removeLsiBeam(LsiBeams $lsiBeam)
{
if (!$this->lsiBeams->contains($lsiBeam)) {
return;
} else {
$lsiBeam->setProposalLsi(null);
$this->lsiBeams->removeElement($lsiBeam);
}
return $this;
}
}
LsiBeam
class LsiBeam
{
/**
* #ORM\ManyToOne(targetEntity="ProposalLsi", inversedBy="lsiBeams")
*/
private $proposalLsi;
public function setProposalLsi(?ProposalLsi $proposalLsi)
{
$this->proposalLsi = $proposalLsi;
}
}
Related
I have the following structure:
Category property that contains link to property and its value:
<?php
class CategoryProperty
{
// ...
/**
* #var Property
*
* #ORM\ManyToOne(targetEntity="App\Entity\Property")
* #ORM\JoinColumn(onDelete="cascade", nullable=false)
*/
private $property;
/**
* Набор значений свойства доступных в product builder, null если любое значение.
*
* #var PropertyValueEntry
* #Assert\Valid
*
* #ORM\OneToOne(targetEntity="App\Entity\Properties\PropertyValues\PropertyValueEntry",
* cascade={"persist", "remove"})
*/
private $propertyValue;
// ...
}
Abstract property value type with a discriminator map:
<?php
/**
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="type", type="integer")
* #ORM\DiscriminatorMap({
* "1": "StringValue",
* "2": "IntegerValue",
* "3": "BooleanValue",
* "4": "TextValue",
* "6": "EnumValue",
* "7": "SetValue",
* "9": "LengthValue",
* "10": "AreaValue",
* "11": "VolumeValue",
* "12": "MassValue",
* })
* #ORM\Table(name="properties_values__value_entry")
*/
abstract class PropertyValueEntry
{
/**
* #var Property
*
* #ORM\ManyToOne(targetEntity="App\Entity\Property")
*/
private $property;
public function __construct(Property $property)
{
$this->property = $property;
}
public function getProperty(): Property
{
return $this->property;
}
/**
* #return mixed
*/
abstract public function getValue();
/**
* #param mixed $value
*/
abstract public function setValue($value): void;
}
And a sample concrete value type:
<?php
/**
* #ORM\Entity
* #ORM\Table(name="properties_values__integer_value")
*/
class IntegerValue extends PropertyValueEntry
{
/**
* #var int
* #Assert\NotNull
*
* #ORM\Column(type="integer")
*/
private $value = 0;
public function getValue(): int
{
return $this->value;
}
/**
* #param int|null $value
*/
public function setValue($value): void
{
if (!\is_int($value)) {
throw new InvalidArgumentException('BooleanValue accepts integer values only');
}
$this->value = $value;
}
}
For some reason, when form is submitted, instead of updating a value for IntegerValue, a new entity gets created, and new row in properties_values__value_entry / properties_values__integer_value. I tried tracking through the $this->em->persist($entity), where $entity is CategoryProperty, and it seems that IntegerValue gets marked as dirty and created anew. How can I track the cause of this happening? My form processing is pretty standard:
<?php
public function editAction(): Response
{
$id = $this->request->query->get('id');
$easyadmin = $this->request->attributes->get('easyadmin');
$entity = $easyadmin['item'];
$isReload = 'reload' === $this->request->request->get('action');
$editForm = $this->createForm(CategoryPropertyType::class, $entity, [
'category' => $this->getCatalog(),
'is_reload' => $isReload,
]);
$deleteForm = $this->createDeleteForm($this->entity['name'], $id);
$editForm->handleRequest($this->request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
if (!$isReload) {
$this->em->persist($entity);
$this->em->flush();
return $this->redirectToReferrer();
}
}
return $this->render($this->entity['templates']['edit'], [
'form' => $editForm->createView(),
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
]);
}
UPDATE #1
What I already tried:
Retrieve category property by ID from entity manager through
$entity = $this->em->find(CategoryProperty::class, $id);
Altogether it seems this may be related to the fact that I have a dynamic form being created based on the selection. When I add a category property, I display a dropdown with a list of property types (integer, string, area, volume etc), and after selection a new form for that property is displayed. Though this works fine and adds new property without a problem, it seems that the code for EDITING same property is missing something, and instead of update it creates it anew.
Possibility #1: Load entity from entity manager directly
You don't appear to be retrieving an existing entity to modify at all.
$entity = $easyadmin['item'];
Shouldn't this be using Doctrine to retrieve an existing entity? For example:
if (!($entity = $this->getRepository(CategoryProperty::class)->findOneById($id))) {
throw $this->createNotFoundException("Category property not found.");
}
Semi-related: You may also want to check that a integer ID was specified at all, as $id = $this->request->query->get('id'); is very assumptive:
if (intval($id = $this->request->query->get('id')) < 1) {
throw $this->createNotFoundException("Category property not specified.");
}
Possibility 2: Missing identifier reference with one-to-one relationship
I think you may be getting duplication because CategoryProperty doesn't persist any reference to a PropertyValueEntry.
/**
* Набор значений свойства доступных в product builder, null если любое значение.
*
* #var PropertyValueEntry
* #Assert\Valid
*
* #ORM\OneToOne(targetEntity="App\Entity\Properties\PropertyValues\PropertyValueEntry", cascade={"persist", "remove"})
*/
private $propertyValue;
However PropertyValueEntry doesn't have an inverse relationship back to CategoryProperty.
A unidirectional one-to-one is fine, but it must have a #ORM\JoinColumn directive to ensure the identifier of the foreign PropertyValueEntry is persisted. Otherwise an edit form won't have any information to know which existing PropertyValueEntry (or derivative) it needs to edit. This is why your "properties_values__value_entry" form field is being reset with a new instance of PropertyValueEntry (or derivative) created when submitting the form.
You've not shown the source for entity class Property so I can't inspect for any further issues in your entity relationships.
Thanks to everyone participating, I have been reading through Symfony documentation and came across the 'by_reference' form attribute. Having considered that my form structure overall looks like this:
Category => CategoryPropertyType => PropertyValueType => [Set, Enum, Integer, Boolean, String, Volume]
for the form, I decided to set it to true in PropertyValueType configureOptions method. As it is explained in the documentation, with it being set to false, the entity is getting cloned (which in my case is true), thus creating a new object at the end.
Note that I'm still learning Symfony and will be refining the answer when I get a better understanding of what's going on behind the scenes.
I have two entities, for products and translations:
class ProductEntity
{
/**
* #Id
* #var string
* #Column(type="string", length=3)
*/
protected $code;
/**
* #OneToMany(targetEntity="ProductTranslationEntity", mappedBy="product")
*/
private $translations;
public function __construct()
{
$this->translations = new ArrayCollection();
}
/.../ getters and setters
public function addTranslation(ProductTranslationEntity $productTranslation)
{
$this->translations->add($productTranslation);
}
public function clearTranslations()
{
$this->translations->clear();
}
}
.
class ProductTranslationEntity
{
/**
* #ManyToOne(targetEntity="ProductEntity", inversedBy="translations")
* #JoinColumn(name="product_code", referencedColumnName="code", onDelete="CASCADE")
* #Id
*/
private $product;
/**
* #var string
* #Column(type="string", name="language_code", length=5)
* #Id
*/
protected $languageCode;
/**
* #var string
* #Column(type="string", name="product_name", length=128)
*/
protected $productName;
/.../ getters and setters
}
I like to replace all translations with new ones, from array like that:
['en' => ['name' => 'name_en'], 'de' => ['name' => 'name_de']];
Because in this array I have set of all supported languages the bast way I can see is to remove all existing translations and put new ones:
$product // Existing product entity
$product->clearTranslations();
$this->entityManager->flush($product);
foreach ($translations as $code => $translation) {
$t = new ProductTranslationEntity();
$t->setProduct($product);
$t->setLanguageCode($code);
$t->setProductName($translation['name']);
$this->entityManager->persist($t);
$product->addTranslation($t);
}
$this->entityManager->flush($product);
This solution doesn't work because after first $this->entityManager->flush($product); there are still translations in database so i get error about duplicates.
What have I done wrong in my solution? Or maybe there is another way to solve this kind of issue?
As Doctrine documentation refers:
Changes made only to the inverse side of an association are ignored.
Make sure to update both sides of a bidirectional association (or at
least the owning side, from Doctrine's point of view).
So to properly clear the translations of a product you should change the clearTranslations() function inside Product entity to:
public function clearTranslations()
{
foreach ($this->translations as $translation) {
$translation->setProduct(null);
}
$this->translations->clear();
}
so that you also update the owning side of the association before removal.
This maybe a bit overload but still it does not use extra requests to database:
$current_translations = $product->getTranslations();
foreach ($translations as $code => $translation) {
$translation_found = false;
foreach ($current_translations as $current_translation) {
if ($current_translation->getLanguageCode() === $code) {
// you've found the translation - replace value
$current_translation->setProductName($translation['name']);
$translation_found = true;
break;
}
}
if (!$translation_found) {
// translation with such code not found - add a new one
$t = new ProductTranslationEntity();
$t->setProduct($product);
$t->setLanguageCode($code);
$t->setProductName($translation['name']);
$this->entityManager->persist($t);
$product->addTranslation($t);
}
}
$this->entityManager->persist($product);
Use orphanRemoval=true:
/**
* #OneToMany(targetEntity="ProductTranslationEntity", mappedBy="product", orphanRemoval=true)
*/
private $translations;
I'm struggling with a symfony2 form. Basically i would like to manage User's preference to receive (or not) an email for each type of action an User could do.
Here my schema :
User (extending FOSUB)
EmailUserPreference
class EmailUserPreference {
public function __construct(User $user, \Adibox\Bundle\ActionBundle\Entity\ActionType $actionType) {
$this->user = $user;
$this->actionType = $actionType;
$this->activated = true;
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Adibox\Bundle\UserBundle\Entity\User", inversedBy="id")
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity="Adibox\Bundle\ActionBundle\Entity\ActionType", inversedBy="id")
*/
private $actionType;
/**
* #ORM\Column activated(type="boolean")
*/
private $activated;
/*getters / setters ... */
}
ActionType
class ActionType
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $value
*
* #ORM\Column(name="value", type="string", length=255)
*/
private $value;
/* and some others */
}
Here, i build my form EmailUserPreferenceType :
class EmailUserPreferenceType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('emailPreference', 'entity', array(
'class' => 'AdiboxActionBundle:ActionType',
'property' => 'value',
'expanded' => true,
'multiple' => true,
'query_builder' => function(\Adibox\Bundle\ActionBundle\Entity\ActionTypeRepository $er) {
return $er->getAllActionsWithPreferences();
}
));
}
public function getName() {
return 'emailUserPreference';
}
public function getDefaultOptions(array $options) {
return array('data_class' => 'Adibox\Bundle\UserBundle\Entity\EmailUserPreference');
}
}
And finally the ActionTypeRepository with the function called in the FormType :
class ActionTypeRepository extends EntityRepository {
public function getAllActionsWithPreferences() {
$arrayActionWithPreferences = array(
'share',
'refuse',
'validate',
'validatePayment',
'createPayment',
'estimateChangeState',
'comment',
'createRepetition',
'display',
'DAFLate',
);
$qb = $this->createQueryBuilder('a');
$qb->where($qb->expr()->in('a.value', $arrayActionWithPreferences));
return $qb;
}
}
At this point, I thought it was OK : i got a good rendering, with the right form. But in fact, each checkbox has the same form name than the other. In other words each time the form is submitted, it only send in post a $builderemailUserPreference[emailUserPreference][] data. Obviously, it does not work as i expected.
I show these posts
http://sf.khepin.com/2011/08/basic-usage-of-the-symfony2-collectiontype-form-field/
Here he's using a widget Collection. I'm not sure i should use it or entity (like i did). But what i can read from http://symfony.com/fr/doc/current/reference/forms/types/collection.html, it seems more like an embedding form than an entity.
And finally i saw this : symfony2 many-to-many form checkbox
This one is using (indeed) Collection and many-to-many relations. I read somewhere (can't find the link anymore) that i can't use it since i need to add some attributes to the relation (in this case bool activated). I'm pretty sure the solution is near the link above, but can't find the good way to reach it.
Thank you in advance.
Any advice on what i'm doing wrong or if i should use Collections instead of Entity would be appreciated.
I'm working on a form with 3 entities :
order (idorder)
support reference table (idsupport)
link table (idorder, idsupport)
And when i try to select one or more support i got this error:
Catchable Fatal Error: Argument 1 passed to Myapp\MyBundle\Entity\PcastCmdsupports::setIdsupports() must be an instance of Myapp\MyBundle\Entity\PcastSupports, instance of Doctrine\Common\Collections\ArrayCollection given,
called in C:\wamp\www\php\Symfony\vendor\symfony\src\Symfony\Component\Form\Util\PropertyPath.php on line 347 and defined in C:\wamp\www\php\Symfony\src\Myapp\MyBundle\Entity\PcastCmdsupports.php line 62
Since i already created my link table i saw on the web that i can simply create 2 Many-To-One relation in my link table :
/**
* #var PcastSupports
*
* #ORM\ManyToOne(targetEntity="PcastSupports")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="IDSUPPORTS", referencedColumnName="IDSUPPORTS")
* })
*/
private $idsupports;
/**
* #var PcastOrder
*
* #ORM\ManyToOne(targetEntity="PcastOrder")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="IDORDER", referencedColumnName="IDORDER")
* })
*/
private $idorder;
and my setters and getters :
/**
* Set idsupports
*
*/
public function setIdsupports(\Myapp\MyBundle\Entity\PcastSupports $idsupports)
{
$this->idsupports = $idsupports;
}
/**
* Get idsupports
*
*/
public function getIdsupports()
{
return $this->idsupports;
}
/**
* Set idorder
*
*/
public function setIdcommande(\Myapp\MyBundle\Entity\PcastOrder $idorder)
{
$this->idorder = $idorder;
}
/**
* Get idorder
*
*/
public function getIdorder()
{
return $this->idorder;
}
In my order form i can choose one or many supports so i created my form like this:
$form_clips = $this->createFormBuilder($cmdclips)
->add('idorder', new CmdsupportsType)
->getForm();
And finally my supportsType form:
$builder
->add('idsupports', 'entity', array(
'class' => 'MyappMyBundle:PcastSupports',
'property' => 'name',
'expanded' => true,
'multiple' => true,
'query_builder' => function(EntityRepository $er)
{
return $er->createQueryBuilder('pts')
->orderBy('pts.idsupports','ASC');
},
));
I'm not using any arraycollection so i don't understand the issue. And the issue happened during this action:
$form_clips->bindRequest($request);
Thank a lot for your help !
I tried to make it work with the many-to-many relation in a simple case (user, company and a user_company entities) but i got a problem when i try to add a company to a user:
Warning: oci_bind_by_name() [<a href='function.oci-bind-by-name'>function.oci-bind-by-name</a>]: Invalid variable used for bind in C:\wamp\www\php\Promocast\Symfony\vendor\doctrine-dbal\lib\Doctrine\DBAL\Driver\OCI8\OCI8Statement.php line 113
I googling a lot but i didn't find anything on this error... According to stack trace the error is when doctrine try to add the company object :
array('column' => ':param10', 'variable' => object(PcastCompany), 'type' => '1')
My user entity (societe = company):
/**
* #ORM\ManyToMany(targetEntity="PcastSociete", inversedBy="users")
* #ORM\JoinTable(name="PcastLienusersociete",
* joinColumns={#ORM\JoinColumn(name="ImUser_iduser", referencedColumnName="iduser")},
* inverseJoinColumns={#ORM\JoinColumn(name="PcastLienusersociete_idsociete", referencedColumnName="idsociete")}
* )
*/
private $societes;
public function getSocietes()
{
return $this->societes;
}
public function addSociete(\Myapp\MyBundle\Entity\PcastSociete $societe)
{
$this->societes[] = $societe;
}
My company entity:
/**
* #ORM\ManyToMany(targetEntity="ImUser", mappedBy="societes")
*/
private $users;
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
If anybody have any idea...
Thanks
You should not have an entity representing the link table. If you annotate both your entities correctly, Doctrine will handle the creation of the link table by itself.
Moreover, you do not need any link table to do a Many-to-One relationship in the first place, what you want to do is use the Many-to-Many annotations in both entities.
http://readthedocs.org/docs/doctrine-orm/en/latest/reference/association-mapping.html?highlight=many%20to%20one#many-to-many-bidirectional
Start with the basics. I was curious about something else concerning ManyToMany so I grabbed your entities as a test case. Before diving into forms and such, make sure you can execute a simple test case from the command line such as:
use Zayso\ArbiterBundle\Entity\PcastSociete as Company;
use Zayso\ArbiterBundle\Entity\ImUser as User;
protected function test1()
{
$em = $this->getContainer()->get('doctrine.orm.entity_manager');
$company = new Company();
$em->persist($company);
$user = new User();
$user->addSociete($company);
$em->persist($user);
$em->flush();
}
For entities I used:
namespace Zayso\ArbiterBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
*/
class ImUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer",name="iduser")
* #ORM\GeneratedValue
*/
protected $id;
public function getId() { return $this->id; }
/**
* #ORM\ManyToMany(targetEntity="PcastSociete", inversedBy="users")
* #ORM\JoinTable(name="PcastLienusersociete",
* joinColumns={#ORM\JoinColumn(name="ImUser_iduser", referencedColumnName="iduser")},
* inverseJoinColumns={#ORM\JoinColumn(name="PcastLienusersociete_idsociete", referencedColumnName="idsociete")}
* )
*/
private $societes;
public function getSocietes()
{
return $this->societes;
}
public function addSociete(PcastSociete $societe)
{
$this->societes[] = $societe;
}
public function __construct()
{
$this->societes = new ArrayCollection();
}
}
namespace Zayso\ArbiterBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
*/
class PcastSociete
{
/**
* #ORM\Id
* #ORM\Column(type="integer", name="idsociete")
* #ORM\GeneratedValue
*/
protected $id;
public function getId() { return $this->id; }
/**
* #ORM\ManyToMany(targetEntity="ImUser", mappedBy="societes")
*/
private $users;
public function __construct()
{
$this->users = new ArrayCollection();
}
}
Get the above working then we can move on to the forms problem.
I am having issues saving the selections made in a entity form field with multiple=true.
The selections come through when $form->bindRequest($request) is called but don't persist in the database when flush is called.
Here is the relevant controller code:
$news_item = new News();
$form = $this->createFormBuilder($news_item)
->add('products', 'entity',
array('class' => 'AcmeDemoBundle:Product',
'multiple' => TRUE))
->getForm();
$request = $this->getRequest();
if($request->getMethod() == "POST") {
$form->bindRequest($request);
if($form->isValid()) {
$this->em->persist($news_item);
$this->em->flush();
}
}
I have checked the $news_item object after $form->isValid() and a count($news_item->getProducts()) returns the correct number of items. The $news_item itself is saved in the DB but the ManyToMany relationship isn't being saved.
Here are the entities for reference (clipped for brevity):
/**
* #ORM\Entity
* #ORM\Table(name="Product")
*/
class Product {
/*
* #ORM\Id #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="News", inversedBy="products")
*/
protected $news_items = null;
public function __construct() {
$this->news_items = new ArrayCollection();
}
}
/**
* #ORM\Entity
* #ORM\Table(name="News")
*/
class News {
/**
* #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Product", mappedBy="news_items")
*/
protected $products = null;
public function __construct() {
$this->products = new ArrayCollection();
}
}
I think you are missing $product->addNewsItem($news_item) and $news_item->addProduct($product) in your code this because in bi-directional associations (seems your case) you have to update the fields on both sides.
To avoid this you can set the cascade option on both sides of the association:
#ORM\ManyToMany(targetEntity="Product", mappedBy="news_items",
cascade={"persist", "remove"})
This way your code will work. You can choose the appropriate cascade options looking at here.
I'm not having the same problem that you are having, but I needed to be able to load FixtureData using similar entities. I was referred to this documentation: http://www.doctrine-project.org/docs/orm/2.1/en/reference/working-with-associations.html and I believe it's going to solve my problem. I hope this works for you too.
JS