Failed to set up a ManyToMany - php

I want to be able to select a school (that has its own entity) while creating a mission (also has its entity)
Since a school can have several missions, and you can select several schools at the mission's creation, I used a ManyToMany.
The problem is that after creating this "ManyToMany", generating the entities and updating my schema, Symfony created a table, but left it totally empty, without the two columns that I asked for. I'm not really used to Symfony nor to the ManyToMany system, so I might have done some mistake without noticing it, still I find this weird.
Here's the interesting part of my ecole (school) entity:
class Ecole{
// ...
/**
* #ORM\ManyToMany(targetEntity="MissionBundle\Entity\Mission", mappedBy="ecolesDispo")
*/
protected $missionsDispos;
// ...
/**
* Add missionsDispo
*
* #param \MissionBundle\Entity\Mission $missionsDispo
*
* #return Ecole
*/
public function addMissionsDispo(\MissionBundle\Entity\Mission $missionsDispo)
{
$this->missionsDispos[] = $missionsDispo;
return $this;
}
/**
* Remove missionsDispo
*
* #param \MissionBundle\Entity\Mission $missionsDispo
*/
public function removeMissionsDispo(\MissionBundle\Entity\Mission $missionsDispo)
{
$this->missionsDispos->removeElement($missionsDispo);
}
/**
* Get missionsDispos
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getMissionsDispos()
{
return $this->missionsDispos;
}
And here is the interesting part of my mission entity:
/**
* #ORM\ManyToMany(targetEntity="EcoleBundle\Entity\Ecole", inversedBy="missionsDispo")
* #ORM\JoinTable(name="Mission2Ecole",
* joinColumns={#ORM\JoinColumn(name="em_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="me_id", referencedColumnName="id")}
* )
*/
protected $ecolesDispo;
// ...
/**
* Constructor
*/
public function __construct()
{
$this->ecolesDispo = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add ecolesDispo
*
* #param \EcoleBundle\Entity\Ecole $ecolesDispo
*
* #return Mission
*/
public function addEcolesDispo(\EcoleBundle\Entity\Ecole $ecolesDispo)
{
$this->ecolesDispo[] = $ecolesDispo;
return $this;
}
/**
* Remove ecolesDispo
*
* #param \EcoleBundle\Entity\Ecole $ecolesDispo
*/
public function removeEcolesDispo(\EcoleBundle\Entity\Ecole $ecolesDispo)
{
$this->ecolesDispo->removeElement($ecolesDispo);
}
/**
* Get ecolesDispo
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEcolesDispo()
{
return $this->ecolesDispo;
}
After all this was created, I was supposed to get a multi selector with the list of all the schools saved in the database (I already added it to the missionType file), but I get absolutely nothing.
I don't really know if I inverted the annotations, or if the "joinTable" part is correct, but I'm completely lost here.
Does anyone have an idea?
Thank you in advance

Just wrong typo "s"? inversedBy="missionsDispo" >>> inversedBy="missionsDispos"
PS. Official doc here
http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-bidirectional

Related

Add extra option to LoggableListener

I use Loggable to backup changes in Entities.
The default AbstractLogEntry does not have enough columns for my needs.
Thats why i extended the class and added extra getters and setters.
See the code below
/**
* EmployeeBackup
*
* #ORM\Table(name="employee_backup")
* #ORM\Entity(repositoryClass="Gedmo\Loggable\Entity\Repository\LogEntryRepository")
*
*/
class EmployeeBackup extends AbstractLogEntry
{
/**
* #var int
*
* #ORM\Column(name="division_id", type="integer", unique=true)
*/
private $divisionId;
/**
* #return int
*/
public function getDivisionId(): int
{
return $this->divisionId;
}
/**
* #param string $divisionId
*/
public function setDivisionId(string $divisionId): void
{
$this->divisionId = $divisionId;
}
}
The extension is using the class above. So it works.
But now i need to set the divisionId when a new version is stored.
I tried the code below
$loggable = new LoggableListener();
$loggable->setDivision($division);
$evm->addEventSubscriber($loggable);
And this is what i get:
Attempted to call an undefined method named "setDivision" of class "Gedmo\Loggable\LoggableListener".
And thats true because LoggableListener does not have a setDivision function. My question is: Do i need to override the listener and if so, how do i do that?
Thanks ;)

Doctrine and Symfony2 : Association refers to inverse side that doesn't exist error

I have a page address.html.twig , the user can add many addresses in the table UserAddress. when he added his address in the database , the address should be render in the same page that he added his address then he can choose which one he would like to use. Unfortunately the address is not render.
First i thought that i have a problem in my controller action or in my twig page. I even asked a question here about it => here
I verified all my tables in phpmyadmin and all of them are well link but if i'm doing this: php app/console doctrine:schema:validate
i have this error :
[Mapping] FAIL - The entity-class
'FLY\BookingsBundle\Entity\Commandes' mapping is invalid:
* The association FLY\BookingsBundle\Entity\Commandes#user refers to the inverse side field
Application\Sonata\UserBundle\Entity\User#commandes which does not
exist.
[Mapping] FAIL - The entity-class
'FLY\BookingsBundle\Entity\UserAddress' mapping is invalid:
* The association FLY\BookingsBundle\Entity\UserAddress#user refers to the inverse side field
Application\Sonata\UserBundle\Entity\User#address which does not
exist.
Have a look at this picture:
This is my UserAddress.php
/**
* #ORM\ManyToOne(targetEntity="Application\Sonata\UserBundle\Entity\User", inversedBy="address")
* #ORM\JoinColumn(nullable=true)
*/
private $user;
Commandes.php
/**
* #ORM\ManyToOne(targetEntity="Application\Sonata\UserBundle\Entity\User", inversedBy="commandes")
* #ORM\JoinColumn(nullable=true)
*/
private $user;
User.php
/**
* #ORM\Entity(repositoryClass="FLY\UserBundle\Repository\UserRepository")
* #ORM\Table(name="fos_user_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
$this->commandes = new \Doctrine\Common\Collections\ArrayCollection();
$this->address = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #ORM\OneToMany(targetEntity="FLY\BookingsBundle\Entity\Commandes", mappedBy="user", cascade={"remove"})
* #ORM\JoinColumn(nullable=true)
*/
private $commandes;
/**
* #ORM\OneToMany(targetEntity="FLY\BookingsBundle\Entity\UserAddress", mappedBy="user", cascade={"remove"})
* #ORM\JoinColumn(nullable=true)
*/
private $address;
Here you can see my var dump:
User {#124 ▼
#id: 21
-commandes: null
-address: null
}
I've had an issue which has popped up 2-3 times in the last few years, where the mappings were incorrect but the schema update was successful. After the mappings were fixed this wasn't reflected in the schema and symfony assumed it was already up-to-date.
I recommend you try removing the relevent relationships manually from your user, commande and address tables and then run:
php app/console doctrine:schema:update --force
- it may fix your issue.
Heres an example from one of my apps - I've done this for your commandes entity.
You'll be able to piece together your UserAddress Entity from this example yourself!
Here goes:
User.php
/**
* #ORM\OneToMany(targetEntity="FLY\BookingsBundle\Entity\Commandes", mappedBy="commandesUser")
*/
protected $commandes;
User.php - Getters and Setters
/**
* Add commandes
*
* #param FLY\BookingsBundle\Entity\Commandes $commandes
*/
public function addCommandes(\FLY\BookingsBundle\Entity\Commandes $commandes)
{
$this->commandes[] = $commandes;
}
/**
* Get commandes
*
* #return Doctrine\Common\Collections\Collection
*/
public function getCommandes()
{
return $this->commandes;
}
Commandes.php
/**
* #ORM\ManyToOne(targetEntity="Application\Sonata\UserBundle\Entity\User", inversedBy="commandes")
* #ORM\JoinColumn(name="user", referencedColumnName="id")
*/
private $commandesUser;
Commandes.php - Getters and Setters
/**
* Set commandesUser
*
* #param Application\Sonata\UserBundle\Entity\User $commandesUser
*/
public function setCommandesUser(\Application\Sonata\UserBundle\Entity\User $commandesUser = null)
{
$this->commandesUser = $commandesUser;
}
/**
* Get $commandesUser
*
* #return Application\Sonata\UserBundle\Entity\User
*/
public function getCommandesUser()
{
return $this->commandesUser;
}
It's quite likely this doesn't happen to anyone else, but there's a chance.
In my case, this error appeared because there was a duplicate. My entity had 2 fields, which are ManyToOne relationships. And they both had the same inversed names, which gave this error.
So this is the relevant bit of code:
class TaskIngredient
{
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Ingredient", inversedBy="taskIngredients")
* #ORM\JoinColumn(nullable=false)
*/
private $ingredient;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Task", inversedBy="taskIngredients")
* #ORM\JoinColumn(nullable=false)
*/
private $task;
}
The solution was relatively easy. I tried changing the inversedBy name, manually. However this didn't fix it (even after applying php app/console doctrine:schema:update --force and removing the var/cache folder).
So I just:
Removed one of the problematic entities (and it's setter/getter)
Ran the php bin/console make:entity tool and readded the field with a different name
Voilà! Issue fixed.

Set PK from ManyToMany annotations in Doctrine2 entity

I've a ManyToMany relationship between Pais and FabricanteDistribuidor tables defined as follow:
Pais.php
class Pais
{
// column definitions
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\FabricanteDistribuidor", inversedBy="paises", cascade={"persist"})
* #ORM\JoinTable(name="negocio.fabricante_distribuidor_pais", schema="negocio",
* joinColumns={#ORM\JoinColumn(name="fabricante_distribuidor_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="pais_id", referencedColumnName="id")}
* )
*/
protected $fabricanteDistribuidor;
/**
* Add fabricanteDistribuidor
*
* #param AppBundle\Entity\FabricanteDistribuidor $fabricanteDistribuidor
*/
public function addfabricanteDistribuidor(\AppBundle\Entity\FabricanteDistribuidor $fabricanteDistribuidor)
{
$this->fabricanteDistribuidor[] = $fabricanteDistribuidor;
}
/**
* Get fabricanteDistribuidor
*
* #return Doctrine\Common\Collections\Collection
*/
public function getfabricanteDistribuidor()
{
return $this->fabricanteDistribuidor;
}
}
FabricanteDistribuidor.php
class FabricanteDistribuidor
{
// column definitions
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Pais", mappedBy="fabricanteDistribuidor", cascade={"persist"})
*/
protected $paises;
public function __construct()
{
$this->paises = new ArrayCollection();
}
/**
* Set paises
*
* #param AppBundle\Entity\Pais $pais
* #return FabricanteDistribuidor
*/
public function addPaises(\AppBundle\Entity\Pais $pais)
{
$this->paises[] = $pais;
return $this;
}
/**
* Get paises
*
* #return Doctrine\Common\Collections\Collection
*/
public function getPaises()
{
return $this->paises;
}
}
That will generate a table fabricante_distribuidor_pais on the schema negocio with fabricante_distribuidor_id and pais_id FK pointing to the PK on the related tables, that's fine.
Regarding this scenario:
1- It's possible to define fabricante_distribuidor_id and pais_id as PK on the fabricante_distribuidor_pais table? I mean adding some extra annotation or I need to create a external entity and set them as #ORM\Id on the column definition?
2- Are the addXXX and getXXX methods right in my entities? By right I mean: I should add one or many paises (from Pais entity) to FabricanteDistribuidor easily and I don't care about to the inverse relation meaning I will not add FabricanteDistribuidor from a Pais, are them right or do I need to change something?
1- If one id is a primary key doesn't the relation becomes many to one/ one to many ? Even 1to1 if both are PK
2- If you don't care about the inverse you are going to add getters and setters in only one entity yes. You can still change it to a biredictionnal later with the attribute "mappedBy"
Check if an entity exists :
You can do that in your controller :
for example in Pays
$data = $em->getRepository('AcmeBundle:Pais')->findOneByFabricanteDistribuidor($id);
if($data)
{
// the entity is allready persisted
}
else
{
// no, we can persist the entity
}

Symfony2 and Doctrine - OneToMany returns only one result

I have tow entities, Submission and Submission History. When I am trying to get the SubmissionHistories from a specific submission, it returns only one, even if there are more entries.
Any idea why?
Here are the entities.
//Entity Submission
/**
* #ORM\OneToMany(targetEntity="SubmissionHistory", mappedBy="submission")
*/
protected $histories;
public function __construct()
{
$this->histories = new ArrayCollection();
}
/**
* Get histories
*
* #return Doctrine\Common\Collections\Collection
*/
public function getHistories()
{
return $this->histories;
}
Then,
//Entity SubmissionHistory
/**
* #ORM\ManyToOne(targetEntity="Submission", inversedBy="histories")
* #ORM\JoinColumn(name="hash_key", referencedColumnName="hash_key")
*/
protected $submission;
/**
* Get submission
*
* #return SciForum\Version2Bundle\Entity\Submission
*/
public function getSubmission()
{
return $this->submission;
}
I found the problem:
I setup the #Id to be the hash_key in the SubmissionHistory entity, which is wrong. By doing that, all results have been collapsed as if I grouped them by "Fields.id".
By changing the Id to the id field, things works perfectly fine.

Can't use Doctrine PersistentCollection for one of my entities, another I can

I have a pair of associations. They are many-to-many and I use an explicitly created entity to join them so I can have metadata about the relationship. Though they are identical, one works and the other doesn't. Worse, last week, they both worked and I haven't touched them since. In MuSQL Workbench, I can select the correct data.
When I extract data into an array for one, life is good. When I try for the other, I get:
Call to a member function setValue() on a non-object
I also get it when I try to count() it, access it ($blah[0]) or iterate over it (foreach).
When I execute:
echo get_class($inData)."<BR>";
echo get_class($inData->accountPurchaseNodes)."<BR>";
echo get_class($inData->accountPurchaseNodes[0])."<BR>";
echo "<HR>";
echo get_class($inData)." x<BR>";
echo get_class($inData->purchaseOrderNodes)."<BR>";
echo get_class($inData->purchaseOrderNodes[0])."<BR>";
echo "<HR>";
exit;
I get:
GE\Entity\Purchase
Doctrine\ORM\PersistentCollection
GE\Entity\AccountPurchaseNode
GE\Entity\Purchase
Doctrine\ORM\PersistentCollection
( ! ) Fatal error: Call to a member function setValue() on a non-object in
/Users/tqwhite/Documents/webdev/goodEarth/goodearth.com/library/
Doctrine/ORM/PersistentCollection.php on line 168
Below, I include the pertinent parts of the entity definitions. I have burned hours trying this and that. I will be immensely grateful for your suggestions.
THIS ONE WORKS:
//==Purchase Entity=====================================
/**
* #param \Doctrine\Common\Collections\Collection $property
* #OneToMany(targetEntity="AccountPurchaseNode", mappedBy="account", cascade={"persist", "remove"});
*/
private $accountPurchaseNodes;
//in __construct()
$this->accountPurchaseNodes = new \Doctrine\Common\Collections\ArrayCollection();
//==AccountPurchaseNode Entity=====================================
/**
*
* #ManyToOne(targetEntity="Purchase", cascade={"all"}, fetch="EAGER")
* #JoinColumn(name="purchaseRefId", referencedColumnName="refId")
*
**/
private $purchase;
/**
*
* #ManyToOne(targetEntity="Account", cascade={"all"}, fetch="EAGER")
* #JoinColumn(name="accountRefId", referencedColumnName="refId")
*
**/
private $account;
//==Account Entity=====================================
/**
* #param \Doctrine\Common\Collections\Collection $property
* #OneToMany(targetEntity="AccountPurchaseNode", mappedBy="purchase", cascade={"persist", "remove"});
*/
private $accountPurchaseNodes;
//in __construct()
$this->accountPurchaseNodes = new \Doctrine\Common\Collections\ArrayCollection();
THIS ONE DOES NOT
//==Purchase =====================================
/**
* #param \Doctrine\Common\Collections\Collection $property
* #OneToMany(targetEntity="PurchaseOrderNode", mappedBy="purchases", cascade={"persist", "remove"});
*/
private $purchaseOrderNodes;
//in __construct()
$this->purchaseOrderNodes = new \Doctrine\Common\Collections\ArrayCollection();
//==PurchaseOrderNode =====================================
/**
*
* #ManyToOne(targetEntity="Purchase", cascade={"all"}, fetch="EAGER")
* #JoinColumn(name="purchaseRefId", referencedColumnName="refId")
*
**/
private $purchase;
/**
*
* #ManyToOne(targetEntity="Order", cascade={"all"}, fetch="EAGER")
* #JoinColumn(name="orderRefId", referencedColumnName="refId")
*
**/
private $order;
//==Order =====================================
/**
* #param \Doctrine\Common\Collections\Collection $property
* #OneToMany(targetEntity="PurchaseOrderNode", mappedBy="order", cascade={"persist", "remove"});
*/
private $purchaseOrderNodes;
//in __construct()
$this->purchaseOrderNodes = new \Doctrine\Common\Collections\ArrayCollection();
It was an error in a referencing entity purchases. It says mappedBy="purchases". It should be purchase.
Please note, the consequences of this error were impossible. It produced a huge data structure that could not be listed in almost any useful way. It gave bizarre results when touched.
The solution to this problem was that the mappedBy field name was incorrect. It did not match the actual name in the target entity (in this case, error in the Purchase entity misspelled the target association name in PurchaseOrderNodes).
It was made much more difficult to see because of the naming convention of plural table names. Watch out for that inflection!

Categories