Doctrine2 innerJoin between two tables without association defined - symfony

I'm trying to join a table that has no association defined in my config file. Why? Because I don't want to pollute this entity (Section) because many other entity can be related to this one with a "Many to One" relation. So, I define the relation only on one side, so it doesn't pollute my Section entity.
What I'm trying to do is :
// Find all sections with this bundle linked
$query = $this->getEntityManager()->getRepository('CompanyBackendSectionBundle:Section')->createQueryBuilder('s')
->select('s', 'st')
->innerJoin('s.translations', 'st')
->innerJoin('s.sectionBundles', 'sb')
->innerJoin('Company\Backend\FaqBundle\Entity\FaqQuestion', 'fq')
->where('st.locale = :locale')
->andWhere('sb.bundle = :bundleId')
->orderBy('st.name')
->setParameters(array(
'locale' => $this->getLocale(),
'bundleId' => $bundle->getId()
));
The problem is with "->innerJoin('Company\Backend\FaqBundle\Entity\FaqQuestion', 'fq')", I got :
[Semantical Error] line 0, col 179 near 'fq WHERE st.locale': Error: Identification Variable Company\Backend\FaqBundle\Entity\FaqQuestion used in join path expression but was not defined before.
Is there a way to do it other than using Doctrine Native Query?

No. Doctrine Query Language needs you to define the relation in the direction you wanna use it...

Related

How can I join two tables without association?

I try to combine two arrays in Symfony that do not have an association field. In documents the field "uuid" is actually the "documentId" in data. Here my approach:
$builder = $this->em->createQueryBuilder();
$result = $builder->select('documents')
->from('App:Documents', 'documents')
->leftJoin('data', 'data')
->andWhere('documents.uuid = data.documentId')
->andWhere('data.fields = :id')
->setParameter('id', 2)
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
But I get the error message that documents has no association data.
You are quite close, but lack a few things.
You need to be more precise with your join and specify which entity is targeted (if there is no relation or inheritance).
// If your entity name is called Data
->leftJoin(Data::class, 'data', 'WITH','data.documentId = documents.uuid')
Let's say you are creating your method from the Documents repository (which by the way should be in singular instead of plural).
Your method would look like this:
$result = $this->createQueryBuilder('documents')
->select('documents as document, data as myData')
->leftJoin(Data::class, 'data', \Doctrine\ORM\Query\Expr\Join::WITH,'data.documentId = documents.uuid')
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
But I think there may be an issue with your schema if there is no relation between two entities that are clearly related.

Symfony Many-to-many query

I have a question about Symfony's Many-to-many relationships. I have a query, that tries to get all the fields of an entity (outside this part), and on top of that query, it adds the following:
$queryBuilder
->leftJoin('AppBundle:Location', 'location',
Join::WITH, 'location.id IN (entity.locations)')
->andWhere('location.institute=:institute')
->setParameter('institute', $user->getInstitute());
On that entity, a Many-to-many relationship is present: entity has a m2m relationship with location. Now I try to get all entities that have the same institute as the user has.
So I query the locations, and check if the institute of the locations have the same institute.
However, I then get
[Syntax Error] line 0, col 118: Error: Expected Literal, got 'entity'
What should I be doing different? I understand it goes wrong with the IN part of the query.
I think your entity.locations is a variable.
If so, you need to add : in front of and setParameter as well.
Change your code to:
$queryBuilder
->leftJoin('AppBundle:Location', 'location', Join::WITH, 'location.id IN (:locations)')
->setParameter('locations', entity.locations);
->andWhere('location.institute=:institute')
->setParameter('institute', $user->getInstitute());
Please let me know if this solve your issue, thanks!
In the end, I found out that the answer is as follows:
$queryBuilder
->leftJoin('AppBundle:Location', 'location',
Join::WITH, 'location MEMBER OF entity.locations')
->andWhere('location.institute=:institute')
->setParameter('institute', $user->getInstitute());

Cannot select entity through identification variables without choosing at least one root entity alias

Ads entity is described by geographic information: Country> Region>County. The Ads entity is only linked with County. Consequently, retrieving Ads by countries will require us joining entities twice.
My goal is counting the number of Ads for a given country. For that, I tried this DQL query but without success:
public function getMotorsAdsCountByCountry($slug){
$qb = $this->_em->createQueryBuilder()
->select("m.id, COUNT(m.id) AS cnt")
->from("MinnAdsBundle:MotorsAds", "m")
->join("m.county","county")->addSelect("county")
->join("county.region","region")->addSelect("region")
->join("region.country","country")->addSelect("country")
->where("country.slug=:slug")
->setParameter(":slug", $slug);
return $qb->getQuery()->getSingleScalarResult();
}
The error I got is:
[Semantical Error] line 0, col -1 near 'SELECT m.id,': Error: Cannot
select entity through identification variables without choosing at
least one root entity alias.
I have even seen a post regarding the same error in this link but without success.
I found the solution:
$qb = $this->_em->createQueryBuilder()
->select("COUNT(m.id) AS cnt")
->from("MinnAdsBundle:MotorsAds", "m")
->join("m.county","county")
->join("county.region","region")
->join("region.country","country")
->where("country.slug=:slug")
->setParameter(":slug", $slug);
I have just remove the addSelect() in addition to the modification of the select().
try changing
->select("m.id, COUNT(m.id) AS cnt")
to
->select("m, COUNT(m.id) AS cnt")
or change hydration to array
this is known as Doctrine limitation you should first join with MotorAds Entity like this
from('MinnAdsBundle','mi')->leftJoin(MotorsAds::class,'m','WITH','mi.motorsAds = m');
then you can select form MotorsAds directly
refer to this answer

Symfony2 QueryBuilder join ON and WITH difference

I'm new with Symfony2 and I built successfully my first join through QueryBuilder and Doctrine 2.
Probably this is a stupid question but both on-line and in the Symfony2's methods I was unable to find anything for understanding the difference between the join clauses "WITH" and "ON".
For example this is my join code:
->leftJoin('EcommerceProductBundle:ProductData', 'pdata', 'WITH', 'prod.id = IDENTITY(pdata.product)')
It works good but if I put ON instead of WITH I get the following error:
[Syntax Error] line 0, col 200: Error: Expected
Doctrine\ORM\Query\Lexer::T_WITH, got 'ON'
Why? I've seen among the objects that there are both the T_ON and T_WITH like join clauses, but which is their usage difference? What is their uses like?
#florian gave you the correct answer but let me try to explain it on example:
In sql, joins are done like this:
SELECT * FROM category
LEFT JOIN product ON product.category_id = category.id
(or something like this)
Now in Doctrine, you don't need to use ON clause because doctrine knows that from relations annotations in your entities. So above example would be:
// CategoryRepository.php
public function getCategoriesAndJoinProducts()
{
return $this->createQueryBuilder("o")
->leftJoin("o.products", "p")->addSelect("p")
->getQuery()->getResult() ;
}
Both would fetch all categories and join products associated with them.
Now comes the WITH clause. If you want to join only products with price bigger than 50, you would do this in SQL:
SELECT * FROM category
LEFT JOIN product ON product.category_id = category.id AND product.price>50
In Doctrine:
// CategoryRepository.php
public function getCategoriesAndJoinProductsWithPriceBiggerThan($price)
{
return $this->createQueryBuilder("o")
->leftJoin("o.products", "p", "WITH", "p.price>:price")
->setParameter("price", price)->addSelect("p")
->getQuery()->getResult() ;
}
So, in reality you should never, ever use ON if you are using Doctrine. If you have a need for something like that, you can be almost sure that you screwed something else.
In theory, ON permits you to give the full join criterias, while WITH permits to add additional criterias to the default ones (IMHO).
But, what DQL permits is to avoid giving the JOIN criterias:
You just have to say: $qb->leftJoin('prod.pdata', 'pdata');
And doctrine2 will handle the join correctly.
Here is a related question about that: Can I use "ON" keyword in DQL or do I need to use Native Query?

Automatically add a Join statement in findBy magic method

I'm using Symfony2 / Doctrine2.
I'm trying to override the BaseEntityRepository Class so the magic findBy method automatically adds a JOIN on a "translations" relation. It was easy to do in Symfony 1.4/Doctrine 1, because it was manipulating a Doctrine_Query object, so I simply had to $query->addJoin() and it did the trick.
Unfortunately, in Doctrine 2 you only receive an array of criteria as parameter, and that's where I'm stucked.
I got many entities which have a one-to-many relationship with a translation entity.
For exemple : Section as a one-to-many relationship with SectionTranslation
The goal is to retrieve only the "active" sections (active is in SectionTranslation) when using SectionRepository->findAll(); (or even findBy).
The wanted DQL result is : Select * from Section INNER JOIN SectionTranslation ON Section.id = SectionTranslation.translatable_id WHERE SectionTranslation.locale = $locale AND SectionTranslation.active = 1;
Any idea?
The solution could be adding event listener for particular entity and particular method.

Resources