symfony doctrine one-to-many entity setup - symfony

I'm trying to get my head around the entity annotations for a doctrine one to many relationship.
For example, if table_one (T1) is:
email_address (string)
and table_two (T2) is
userid_email (string)
entry (int)
(email_address.table_one = userid_email.table_two) and there are multiple entries in table_two i.e
userid_email=test#email.com,entry=5;
userid_email=test#email.com,entry=6
Do I create the annotation for the T1 Entity
/**
* #ORM\ManyToMany(targetEntity="T1")
* #ORM\JoinTable(name="table_two",
* joinColumns={#ORM\JoinColumn(name="userid", referencedColumnName="userid_email")}
* )
*/
protected entries;
public function __construct()
{
$this->entries = new ArrayCollection();
}
And then in a createQuery I query on T1 :
$query = $em->createQuery('
SELECT u.email, u.entries
FROM AppBundle:T1 u
WHERE u.email = :an_email_address');
For the above query I would always get this error :
Error: Invalid PathExpression. Must be a StateFieldPathExpression
Is there something I am setting up improperly for the relationship?

Your configuration seems to be wrong, try something like:
/**
* #ORM\ManyToMany(targetEntity="T1")
* #ORM\joinColumn={#ORM\JoinColumn(name="userid", referencedColumnName="userid_email")}
* )
*/

Related

Doctrine ManyToMany with as specific field value

I'm trying to create a relation ManyToMany with doctrine (in symfony) that is depending on a field value.
/**
* #ORM\ManyToMany(targetEntity="Label")
* #ORM\JoinTable(
* name="Item_Label",
* joinColumns={#ORM\JoinColumn(name="item_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="label_id", referencedColumnName="id")}
* )
*/
private $labels;
Here we understand that we have to get data from Label via the table Item_label
We are on table Wine
Wine.id <-> Item_Label.item_id
<<< `WHERE Item_Label.item_type = 'wine'` >>>
`Item_Label.label_id` <-> `Label.id`
So, how can i write the WHERE Item_Label.item_type = 'wine' in annotations ?
Or a SqlFilter (I tried but failed) ?
Thanks for your help =)
So, it seems from this SO answer that it's not possible in doctrine.
My workaround was to add a method to my entity class as follows
public function foo($itemLabelRepo)
{
$found = $itemLabelRepo->findBy(['item_type'=>'wine', 'label_id'=>$this->getId()]);
if(count($found)!=1) {
throw new \Exception("Found non-one object from entity role");
}
return $found[0];
}
where $itemLabelRepo would be the repository to "Item_Label" in your case

Doctrine n:m relation Undefined index: joinColumns in BasicEntityPersister.php

My question is strongly related to this one Undefined index: inverseJoinColumns while trying to define ManyToMany relationship between two entities
I am trying to find all the books which have no section. ->findBy(array("section"=>null)
Here is my Entity config:
EditedBooks
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Sections", inversedBy="editedBook")
* #ORM\JoinTable(name="edited_book_has_section",
* joinColumns={
* #ORM\JoinColumn(name="edited_book_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="section_id", referencedColumnName="id")
* }
* )
*/
private $section;
Here is my Entity config:
Sections
/**
* Bidirectional (INVERSE SIDE)
*
* #ORM\ManyToMany(targetEntity="EditedBooks", mappedBy="section")
*/
private $editedBook;
The Error that I am getting
Undefined index: joinColumns in BasicEntityPersister.php
I tryied it also with only
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Sections", inversedBy="editedBook")
* #ORM\JoinTable(name="edited_book_has_section")
*/
or switching the definition but then I receive this error
You cannot search for the association field '\Entity\EditedBooks#section', because it is the inverse side of an association. Find methods only work on owning side associations.
Workaround:
Today I tried to fix my problem with the querybuilder in my editedBooksRepository
$query = $qb->select('books')
->from('Bundle:EditedBooks', 'books')
->leftJoin('books.section', 'sec')
->addSelect('COUNT(sec.id) AS sec_count')
->andWhere('sec_count = 0');
But I receved the following error:
An exception occurred while executing 'SELECT e0_.id AS id0, e0_.doi
AS doi1, e0_.isbn_print AS isbn_print2, e0_.isbn_electronic AS
isbn_electronic3, e0_.publication_date AS publication_date4,
e0_.price_print AS price_print5, e0_.price_electronic AS
price_electronic6, e0_.summary AS summary7, e0_.title AS title8,
e0_.ongoing AS ongoing9, e0_.pages AS pages10, e0_.illustrations AS
illustrations11, e0_.entry_date AS entry_date12, e0_.google_id AS
google_id13, e0_.specialIssue_comment AS specialIssue_comment14,
e0_.deleted AS deleted15, e0_.specialIssue_id AS specialIssue_id16,
COUNT(s1_.id) AS sclr17, e0_.book_series_id AS book_series_id18,
e0_.copyright_id AS copyright_id19, e0_.publisher_id AS publisher_id20
FROM edited_books e0_ LEFT JOIN edited_book_has_section e2_ ON e0_.id
= e2_.editedbooks_id LEFT JOIN sections s1_ ON s1_.id = e2_.sections_id WHERE sclr17 = 0':
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sclr17' in
'where clause'
but to me it seems like sclr17 exists, am I missing something?
The ugly Workaround
I know it is not the right thing to do but sometimes a man has to to what a man has to do:
$noSection = new Sections();
$noSection->setTitle("Sectionless");
//add all the books
$noSection->setEditedBook(new ArrayCollection($books));
//remove the assigned ones
foreach($sections as $section){
$sBooks = $section->getEditedBook();
foreach($sBooks as $b){
$noSection->removeEditedBook($b);
}
}
With the dirty fix it is now working but I am glad for any other solution.
Here is a working example
class Audio
{
/**
* #ORM\ManyToMany(targetEntity="Acme\MyBundle\Entity\Groupe",inversedBy="audios")
*/
private $groupes;
class Groupe
{
/**
* #ORM\ManyToMany(targetEntity="Acme\MyBundle\Entity\Audio",mappedBy="groupes")
*/
private $audios;
Notice how the mappedby and inversedby, as well at the attributes have an "s" at the end. (Groupe => private $groupe s ). Maybe it will help you
Can't you just check with null?
$query = $qb->select('books')
->from('Bundle:EditedBooks', 'books')
->leftJoin('books.section', 'sec')
->where('sec IS NULL');

Unable to retrieve records using a variable in Symfony2, but works if I don't use a variable?

I have three SQL statements in Symfony2, and they all use a variable that contains the record ID (which is passed through using the URL). The first SQL statement works correctly, however, the other two don't. They often result in errors like this:
An exception occurred while executing 'SELECT m0_.name AS name0,
m0_.created AS created1, m0_.event_date AS event_date2,
m0_.description AS description3, m0_.event_type AS event_type4,
m1_.surname AS surname5, m1_.first_name AS first_name6 FROM map_lists
m0_ LEFT JOIN map_list_members m2_ ON (m2_.list_id = m0_.id) LEFT JOIN
map_contacts m1_ ON (m1_.id = m2_.contact_id) WHERE m0_.branch_id = ?
AND m0_.event_type IS NOT NULL AND m1_.id = ? ORDER BY m0_.event_date
DESC' with params {"1":"0","2":{}}:
Catchable Fatal Error: Object of class Doctrine\ORM\Query could not be
converted to string in
F:\wamp\www\centredb\vendor\doctrine\dbal\lib\Doctrine\DBAL\Connection.php
line 1211
The two SQL statements in question are:
// Retrieve Test For That Member
$membertests = $dm->createQuery('
SELECT mt.id, mt.taken, mt.result, mtd.test, mtd.description
FROM InstructorBundle:MapTests mt
LEFT JOIN InstructorBundle:MapTestDescriptions mtd WHERE mtd.id = mt.testDescription
WHERE mt.contact = :member'
)->setParameter('member', '40264');
$memtest = $membertests->getResult();
// Retrieve Events For That Member
$memberevents = $dm->createQuery('
SELECT mli.name, mli.created, mli.eventDate, mli.description, mli.eventType, mc.surname, mc.firstName
FROM InstructorBundle:MapLists mli
LEFT JOIN InstructorBundle:MapListMembers mlm WHERE mlm.list = mli.id
LEFT JOIN InstructorBundle:MapContacts mc WHERE mc.id = mlm.contact
WHERE mli.branch = :centre
AND mli.eventType IS NOT NULL
AND mc.id = :member
ORDER BY mli.eventDate DESC'
)->setParameters(array(
'centre' => $centreid,
'member' => $member
));
$memevent = $memberevents->getResult();
Now, if I remove $member from the Parameters and replace it with the record ID that I'm using during development these SQL statements work. Obviously this isn't ideal, so to find out why these SQL statements fail when using the same variable that the 3rd uses is vital.
The 3rd SQL statement, for reference, is:
// Retrieve Member Details
$member = $dm->createQuery('
SELECT mc.id, mc.surname, mc.firstName
FROM InstructorBundle:MapSubscriptions msu
LEFT JOIN InstructorBundle:MapContacts mc WHERE msu.contact = mc.id
LEFT JOIN InstructorBundle:MapFamilies mf WHERE mc.family = mf.id
WHERE mc.id = :member'
)->setParameter('member', $member);
I've looked at the Entity's of the two tables and the two fields that $member is used to recover the data from. They look like this:
MapTests mt
/**
* #var \MapContacts
*
* #ORM\ManyToOne(targetEntity="MapContacts")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="contact_id", referencedColumnName="id")
* })
*/
private $contact;
/**
* Set contact
*
* #param \Acme\InstructorBundle\Entity\MapContacts $contact
* #return MapTests
*/
public function setContact(\Acme\InstructorBundle\Entity\MapContacts $contact = null)
{
$this->contact = $contact;
return $this;
}
/**
* Get contact
*
* #return \Acme\InstructorBundle\Entity\MapContacts
*/
public function getContact()
{
return $this->contact;
}
MapContacts mc
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
I can't figure it out, it seems fine to me. But obviously something is stopping this from working.
Is your $member variable an object? You need to use integer id as parameter in your query, so replace $member with $member->getId()
This is a really weird issue, as the $member variable works with one query but wouldn't with the other two. However, adding this code seemed to have fixed the issue:
$memberint = intval($member);
This seemed to fix it. The errors dissappeared. However, it doesn't explain really why $member will work with one query and not the other two.
I recommend use dsl, the query language provided by Doctrine. Your second query looks like:
$dm->createQuery()
->select('mli.name, mli.created, mli.eventDate, mli.description, mli.eventType, mc.surname, mc.firstName')
->from('InstructorBundle:MapLists', 'mli')
->leftJoin('mli.list', 'mlm')
->leftJoin('mlm.contact', 'mc')
->where('mli.branch = :centre')
->andWhere('mli.eventType IS NOT NULL')
->andWhere('mc.id = :member')
->orderBy('mli.eventDate', 'DESC')
->setParameters(array(
'centre' => $centreid,
'member' => $member
));
Look at examples here - http://docs.doctrine-project.org/en/latest/reference/dql-doctrine-query-language.html
Everywhere where id is used as a parameter, it is used as integer. And in database, id is always an integer. Doctrine needs your $member as an integer, whereas you are passing a numeric string. I assume that the portion of the code where Doctrine verifies parameters has some type of bug. I suggest that you report this bug at #doctrine channel on freenode.
As a solution for your code, just do typecasting for your $member variable either with intval($member) or (int)$member right in your query.

Symfony2 and Doctrine - Error: Invalid PathExpression. Must be a StateFieldPathExpression

I have an entity that looks like this:
/**
* #Gedmo\Tree(type="nested")
* #ORM\Table(name="categories")
* #ORM\Entity()
*/
class Category extends BaseCategory
{
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="parent")
*/
protected $children;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
*/
protected $parent;
}
and I am trying to run a query like this:
$qb = $this->em->createQueryBuilder()
->select('c.parent')
->from('Category', 'c');
$result = $qb->getQuery()->getArrayResult();
However, I am getting the following error:
[Semantical Error] ... Error: Invalid PathExpression. Must be a StateFieldPathExpression.
How can I select the parent_id field from my table. I have tried a bunch of variations and even if I do something like this:
$qb = $this->em->createQueryBuilder()
->select('c')
->from('Category', 'c');
I get all fields in the table except for the parent_id. This seems like Doctrine is getting in the way. How can I query for this parent_id field? or better yet how can I get all fields in the table including the parent_id
You can use the currently undocumented IDENTITY function to select the FK IDs in a query:
SELECT IDENTITY(c.parent) ...
Solution using createQueryBuilder:
$query->SELECT('pa.id')
->from('Category', 'ca');
$query->join('ca.parent', 'pa');
$result = $query->getQuery()->getArrayResult();
You are selecting an object that is not joined.
Like said in another answer, you have to do something like :
qb->innerJoin("c.parent", "p")
You can change it like this:
->select(array('i.id','identity(i.parent) parent','i.nom'))

Symfony2 building ManyToOne relationship in Entities

I have two entities in a OneToMany relationship, Perfil and IPerfil. Perfil can have several IPerfil's associated:
>
class Perfil
{
/**
* #var integer $id
*
* #ORM\Column(name="id_perfiles", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="SEQUENCE")
* #ORM\SequenceGenerator(sequenceName="P360.perfiles_seq")
* #ORM\OneToMany(targetEntity="IPerfil", mappedBy="id")
*/
private $id;
And the other one:
>
class IPerfil
{
/**
* #var integer $id
* #ORM\ManyToOne(targetEntity="Perfil")
* #ORM\JoinColumn(name="id_perfiles", referencedColumnName="id_perfiles", onDelete="CASCADE")
*/
protected $id;
I'm able to lazyload from IPerfil to Perfil, but not in the other direction (from Perfil to IPerfil), but if I can't do any DQL over IPerfil or createQueryBuilder()->setPameter... Symfony will always return an error like this:
[Semantical Error] line 0, col 9 near 'id_perfiles FROM': Error: Invalid PathExpression. Must be a StateFieldPathExpression.
If I define the field Id with an
#ORM\Column(name="id_perfiles", type="integer")
Then I'm able to build DQL's with the entity, but the relationship won't work anymore.
I'm lost around here... It seems I'm missing something in the relationship definition, but have no clue.
Thanks in advance for any tip.
EDIT
If I use:
$entities=$em->getRepository('usuariosBundle:IPerfil')->findAll(array());
It doen'st gives an error, but I need to filter and order the results.
$entities=$em->getRepository('usuariosBundle:IPerfil')->findBy(array(),array('id' => 'asc', 'descripcion' => 'asc'));
Unrecognized field: id
$query=$em->getRepository('usuariosBundle:IPerfil')->createQueryBuilder('p')
->orderBy('id', 'ASC')
->getQuery();
$entities = $query->getResult();
*[Semantical Error] line 0, col 60 near 'id ASC': Error: 'id' is not defined. *
$entities = $this->get('doctrine')->getEntityManager()->createQuery('SELECT p.id FROM usuariosBundle:IPerfil p ')->getResult();
[Semantical Error] line 0, col 9 near 'id FROM usuariosBundle:IPerfil': Error: Invalid PathExpression. Must be a StateFieldPathExpression.
Use attribute name of class, no column name on dql => 'id'
->orderBy('p.id', 'ASC') and ->createQuery('SELECT p FROM usuariosBundle:IPerfil p ')->getResult(), the name of bundle is usuarios os Usuarios ?
If it is useful to anyone, I finally created a non-persistent attribute in the Perfil entity to attach the the relationship and a collection of IPerfil's there:
/**
* #ORM\OneToMany(targetEntity="IPerfil", mappedBy="id")
*/
private $desc;
Need to declare it as a ArrayCollection:
public function __construct()
{
$this->desc = new \Doctrine\Common\Collections\ArrayCollection();
}
And now I'm able to lazy load in the right direction and do any necessary operation. I suppouse Doctrine couldnt load the collection into id, as it wasn't declared as a collection and it's the ID field.

Resources