Doctrine query builder, select foreign key - php

I have this query :
$qb = $this->_em->createQueryBuilder();
$qb->select('DISTINCT c.account')
->from('ThanksWhoProjectBundle:Comment', 'c')
->leftjoin('c.account', 'a')
->where('c.conversation = ?1')
->setParameters(array(1 => $conversation));
return $qb->getQuery()->getResult();
So, the field Comment.account is a foreign key with my entity Account. I just need to retrieve all differents accounts who are in the conversation.
So, i want to only select the field c.account, but with this query have this error :
[Semantical Error] line 0, col 18 near 'account FROM': Error: Invalid PathExpression. Must be a StateFieldPathExpression. (500 Internal Server Error)
How can i do that ?

You need to use DISTINCT on the joined account id:
$qb = $this->_em->createQueryBuilder();
$qb->select('DISTINCT a.id') // note 'a.id'
->from('ThanksWhoProjectBundle:Comment', 'c')
->leftjoin('c.account', 'a')
->where('c.conversation = ?1')
->setParameters(array(1 => $conversation));
return $qb->getQuery()->getResult();
From the official documentation: http://docs.doctrine-project.org/en/latest/reference/dql-doctrine-query-language.html

"Making this possible is very simple. Just add the property shopId to the product entity as any other field mapping property, and so that it corresponds with the actual column in the database table. Make sure you put this property ABOVE the association property “shop”, otherwise it will not work as expected."
http://pietervogelaar.nl/doctrine-2-use-foreign-key-as-field-in-dql/
Note: I am using a custom hydrator. I did run into issues when using this with the default hydrator.
Great, no more unnecessary joins for read only queries! I'm not sure what the effects would be when trying to update the objects in a result set.

Related

Order By on Joined Entity - Doctrine Query Builder

I have the following query:
$qb = $this->_em->createQueryBuilder();
$qb->select('a')
->from('CatalogueBundle\Entity\Avantage','a')
->leftJoin('a.avantagegrilles', 'g')
...
->orderBy('a.avantageOrdre', 'ASC');
The result of the query is as follows:
An avantage can contain several avantagegrilles. Now there is a variable in entity avantagegrille called avantagegrilleMini and I want to do an order by asc on it; that is, when an avantage is returned, its avantagegrilles are ordered according to their avantagegrilleMini.
I added ->orderBy('g.avantagegrilleMini', 'ASC') to the query but it didn't have any effect. Is what I want to implement possible in Doctrine?
Let's try this line: ->orderBy('g.avantageOrdre', 'ASC');

Conditionnally join table on Doctrine2

I seeked for an answer but anything in my particular case.
I need to join contintionnally table with Doctrine 2, depends on value of a field I have to join on two different foreign keys, here my code :
$qb = $this->entityManager->createQueryBuilder();
$qb ->select('s')
->from('AppBundle:MyTable', 's')
->join('s.firstJoin', 'o')
->join('s.secondJoin', 'd')
->join('AppBundle:joinedView', 'view', Join::WITH,
"(CASE WHEN (d.secondJoinFK = 3)
THEN view.did = d.secondJoinFK
WHEN (d.secondJoinFK = 2)
THEN view.dvid = d.secondJoinFK END)")
->addSelect('d')
->where('s.endDate IS NULL');
However, with this request, Symfony tells me : [Syntax Error] line 0, col 203: Error: Expected Doctrine\ORM\Query\Lexer::T_ELSE, got '='
Moreover, I cannot use native query because I use PagerFanta for rendering template, and PagerFanta needs to have a ORM\Query on input and not ORM\NativeQuery or other.
Unfortunately, I do not have choice and must implement this request with these prerequisites.
Thanks by advance for your help,
It is not possible to do the something like conditional join. You always need to join both tables and specify different join condition.
You can do something like this:
->join('AppBundle:joinedView', 'view1', Join::WITH,
"view1.did = 3")
->join('AppBundle:joinedView', 'view2', Join::WITH,
"view2.dvid = 2")
but honestly I am not sure what are you trying to achieve. Joining tables without a condition which uses some joining column seems a bit pointless.

Symfony Doctrine Group By Query

I have below sql query running fine,
SELECT completed_by, count(*) AS Total
FROM tasks
WHERE completed_by is not null AND status = 1
GROUP BY completed_by
;
Em am doing it with doctrine query builder, but not working returning an error.
$parameters = array(
'status' => 1,
);
$qb = $repository->createQueryBuilder('log');
$query = $qb
->select(' log.completedBy, COUNT(log) AS Total')
->where('log.Status = :status')
->groupBy('log.completedBy')
->setParameters($parameters)
->getQuery();
and getting below error;
[Semantical Error] line 0, col 21 near 'completedBy,': Error: Invalid
PathExpression. Must be a StateFieldPathExpression.
I know this answer can be late, but I struggled with the exact same problem, and did not find any answer on the internet, and I believe a lot of people will struggle in this same issue.
I'm assuming your "completedBy" refers to another entity.
So, inside your repository, you can write:
$query = $this->createQueryBuilder("log")
->select("completer.id, count(completer)")
->join("log.completedBy", "completer")
->where('log.Status = :status')
->groupBy("completer")
->setParameters($parameters)
->getQuery();
This will compile to something like:
SELECT completer.id, count(completer) FROM "YOUR LOG CLASS" log INNER JOIN log.completedBy completer WHERE log.Status=:status GROUP BY completer
Now, You can do another query to get those 'completers', by their ids.
This is wrong: COUNT(log) AS Total. It should be something like COUNT(log.log) AS Total.
When you want to select a column who is a fk for another table (entity), use the IDENTITY function instead of the column name only.
Example: In your case
$parameters = array(
'status' => 1,
);
$qb = $repository->createQueryBuilder('log');
$query = $qb
->select('IDENTITY(log.completedBy), COUNT(log.something) AS Total')
->where('log.Status = :status')
->groupBy('log.completedBy')
->setParameters($parameters)
->getQuery();

How to update multiple fields using query builder in Doctrine2?

I have to update multiple fields, when I tried to update fields in other table using foreign key id using getRepository() and findOneById() getting bug as unrecognised field, so then later tried to implemented it using query builder. but query doesn't get executing getting bug like undefined fields.
This is the code I have tried:
$this->em
->getRepository('Application_Entity_Company', 'c')
->findOneBy(array('c.userId'=>$post['user_id']));
and
$qb->update('Application_Entity_Company', 'c')
->set('c.name', $post['name'])
->set('c.mobile', $post['mobile'])
->set('c.email', $post['email'])
->where($qb->expr()
->eq('c.userId', ':id'))
->setParameter('id', $post['user_id'])
->getQuery()
->execute();
Here userId is the foreign key. I have to update the fields of user details in user entity using the userId.
The problem is with not obvious usage of set method. Second parameter is expected to be an expression instead of the obvious user input.
For sample incorrectly used set code:
$queryBuilder = $entityManager->getRepository()->createQueryBuilder('u');
$queryBuilder->update()
->set('u.userFirstName', 'Michael')
->where('u.userId = :userId')
->setParameter('userId', 111)
->getQuery()
->execute();
SQL representation:
UPDATE user SET user_first_name = Michael WHERE user_id = 111;
You will get following error:
[Semantical Error] line 0, col 49 near 'Michael WHERE': Error:
'Michael' is not defined.
This is because your database assumes Michael is a table column name which for obvious reasons is not defined.
Solution is to either use \Doctrine\ORM\Query\Expr or by binding parameters:
$queryBuilder = $mapper->getRepository()->createQueryBuilder('u');
$queryBuilder->update()
->set('u.userFirstName', ':userFirstName')// Alternatively $queryBuilder->expr()->literal('Michael')
->where('u.userId = :userId')
->setParameter('userId', 111)
->setParameter('userFirstName', 'Michael')
->getQuery()
->execute();

Symfony2/Doctrine2 innerJoin using QueryBuilder

I'm trying to build a innerJoin query using Doctrine2/QueryBuilder.
$repo = $this->getDoctrine()
->getRepository('MyBundle:Models');
$query = $repo->createQueryBuilder('m')
->where('m.id = :id')
->setParameter('id', $id);
Doctrine says:
A join always belongs to one part of the from clause. This is why you
have to specify the alias of the FROM part the join belongs to as the
first argument.
As a second and third argument you can then specify the name and alias
of the join-table and the fourth argument contains the ON clause.
Ex.
$queryBuilder
->innerJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
What I can't understand is that 'phonenumbers' table is referencing to Entity Name or DB Table Name.
What I actually want is, is there any way to explicitly refer to entity like
innerJoin('u', 'MyBundle:phonenumbers', 'p', 'u.id = p.user_id')?
It's a bit confusing when it joins just like that. Can please someone explain that to me?
Help!!
You are working on a DQL level with tables, which means that you actually joining a table, so you just need the table name, not the entity name. The table "phonenumbers might not even had an entity to begin with, this is why Doctrine requests a table name and not an entity name.
Edit
It is actually possible to work with entity names as well as follows (taken from my own code which is working as a charm):
$builder = $this->createQueryBuilder('m');
$builder->innerJoin(
'YourBundle:Category',
'c',
Join::WITH,
$builder->expr()->eq('m.id', 'c.mdl_id')
);
To use the constants from Join you should first:
use Doctrine\ORM\Query\Expr\Join;
But this should also work (taken from documentation which means should work like a charm):
$queryBuilder
->select('id', 'name')
->from('users', 'u')
->innerJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
This is taken form: http://doctrine-orm.readthedocs.org/projects/doctrine-dbal/en/latest/reference/query-builder.html#join-clauses
In fact, you're already referencing explicitely your entity phonenumbers in your second argument of your innerJoin function.
You read the doc and i'll retake it point by point with your request :
Argument 1 : alias of the FROM part, here your m (alias of your models)
Argument 2 : The full name of your entity you want join with your models
Argument 3 : an alias to access it (just like the 'm' of models)
Argument 4 : The join condition. (like the ON part of a sql request)
But with symfony and if you have a relation between your two entities like that :
//AppBundle/Entity/Models
class Models {
/**
* ...
**/
private $id;
/**
* ...
* #ORM\ManyToOne(targetEntity="\AppBundle\Entity\Phone", inversedBy="models")
**/
private $phonenumbers;
...
}
you want to join you just can do :
$repo = $this->getDoctrine()
->getRepository('MyBundle:Models');
$query = $repo->createQueryBuilder('m')
->innerJoin('m.phonenumbers', 'p')
->where('m.id = :id')
->setParameter('id', $id);
To explain that : You just have to pass as first argument, the entity property you want to join (here the phone number of your model) and define it as alias (p for phonenumber to access it in a select)

Categories