Order by count in Doctrine - symfony

I have two classes related via a OneToMany bidirectional relationship. For every subscription a new line will be added to Subscriptions table. I want to get the training list ordered by max subscription number. Here are my entities:
Trainings Entity:
class Trainings
{
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Subscriptions", mappedBy="id_training")
*/
private $subscriptions_lists;
// ...
}
Subscriptions Entity:
class Subscriptions
{
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Trainings" , inversedBy="subscriptions_lists")
* #ORM\JoinColumn(name="id_training", referencedColumnName="id",onDelete="CASCADE")
*/
private $id_training;
QueryBuilder:
$trainings = $em->getRepository('AppBundle:Trainings')
->createQueryBuilder('t')
->innerJoin('t.subscriptions_lists', 'subscription')
->orderBy('COUNT(subscription.id)', 'DESC')
->getQuery()
->getResult();
I'm getting this exception:
[Syntax Error] line 0, col 87: Error: Expected known function, got 'COUNT'

You need to add a field containing the count value and after order by It
try this:
$trainings = $em->getRepository('AppBundle:Trainings')
->createQueryBuilder('t');
$trainings->select('t, COUNT(subscription.id) AS mycount')
->leftJoin('t.subscriptions_lists', 'subscription')
->groupBy('subscription.id_training')
->orderBy('mycount', 'DESC')
->getQuery()
->getResult();

Related

What is wrong with this Doctrine querying on ManyToMany relation

I am trying Symfony 4 and I can't get this query right. The same thing worked OK in Symfony 3. I have 2 entities. One is a person and the other is a day. The relation is ManyToMany. I would like to get all days for a specific person
I tried using MEMBER OF and joining tables, but nothing works for this example.
// Day entity
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Person", inversedBy="days")
*/
private $person;
// Person entity
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Day", mappedBy="person")
*/
private $days;
// Repository function
return $this->createQueryBuilder('d')
->andWhere('d.person = :person')
->setParameter('person', $person)
->getQuery()
->getResult()
;
This is the error I get:
In QueryException.php line 65: [Semantical Error] line 0, col 58 near
'person = :pe': Error: Invalid PathExpression.
StateFieldPathExpression or SingleValuedAssociationField expected.
In QueryException.php line 43:
SELECT d FROM App\Entity\Day d WHERE d.date = :date AND d.person =
:person
The issue is not about Symfony version it's about orm version, i guess
So you could try this by using IDENTITY
return $this->createQueryBuilder('d')
->andWhere('IDENTITY(d.person) = :person')
->setParameter('person', $person)
->getQuery()
->getResult()
;
or
return $this->createQueryBuilder('d')
->leftJoin('d.person', 'p')
->andWhere('p.id = :person')
->setParameter('person', $person)
->getQuery()
->getResult()
;
You can get person related days just from association like $person->getDays()

symfony doctrine one-to-many entity setup

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")}
* )
*/

Doctrine query to search entities based on related entity field

I've ManyToOne relationship in doctrine (Many results to One PollingStation):
/**
* #ORM\ManyToOne(targetEntity="Iballot\CmsBundle\Entity\PollingStation2", inversedBy="results", cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
* #Expose
*/
private $pollingStation2;
I'd like search for all the result that belong to the polling Station that have a name similar to a key word. I try the following method but it does not work:
public function getForSearch($keyWord)
{
$query = $this->_em->createQueryBuilder();
$query
->select('r')
->from('IballotCmsBundle:Result', 'r')
->where($query->expr()->like('p.pollingStation2', $query->expr()->literal('%' . $keyWord . '%')))
//->orderBy('p.', 'ASC')
->getQuery()
->setParameter('keyWord', '%'.$keyWord.'%');
return $query->getQuery()->getResult();
}
I get the following error
[Semantical Error] line 0, col 48 near 'pollingStation2': Error:
Invalid PathExpression. Must be a StateFieldPathExpression.
As said by #Cerad (one more time), you need a JOIN to make the associated entity available while building your query.
Try this :
$query = $this->_em->createQueryBuilder();
$query
->select('r')
->from('IballotCmsBundle:Result', 'r')
->leftJoin('r.pollingStation2', 'p') // The missing join
->where('p.name LIKE :keyword') // where p.name like %keyword%
->setParameter('keyword', '%'.$keyword.'%')
->orderBy('p.name', 'ASC') // order by p.name ASC
->getQuery()
return $query->getResult();
BTW I fixed your orderBy, simplified your where and fixed the keyword parameter that is wrongly defined.
Try putting this method in your Result EntityRepository class:
public function getForSearch($keyWord)
{
$query = $this->createQueryBuilder('r');
$query
->join('r.pollingStation2', 'p')
->where('p.name LIKE :keyword')
->setParameter('keyword', '%' . $keyWord . '%')
//->orderBy('p.', 'ASC')
;
return $query->getQuery()->getResult();
}

Query Builder or Closure or DQL, which is the right one for get ride of this complex SQL query with ManyToMany relationship?

So I've this two entities:
class TipoRegistro
{
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\TipoTramite", inversedBy="tipoRegistros", cascade={"persist"})
* #ORM\JoinTable(name="nomencladores.tipo_registro_tipo_tramite", schema="nomencladores",
* joinColumns={#ORM\JoinColumn(name="tipo_registro_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="tipo_tramite_id", referencedColumnName="id")}
* )
*/
protected $tipoTramites;
}
class TipoTramite
{
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\TipoRegistro", mappedBy="tipoTramites", cascade={"persist"})
*/
protected $tipoRegistros;
}
I need to get all the TipoRegistro associated to TipoTramite trhough ManyToMany relationship as show before as the SQL below shows:
SELECT tr.*
FROM
nomencladores.tipo_registro tr
LEFT JOIN
nomencladores.tipo_registro_tipo_tramite AS trtt
ON (trtt.tipo_registro_id = tr."id")
WHERE
tr.activo = true
AND
trtt.tipo_tramite_id = 1;
I don't know if I can use a custom repository here so my only solution is to use query_builder parameter at form level and this is what I'm doing:
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('tr')
->where('tr.activo = :activo')
->leftJoin('tr.tipoTramites', 'ttr')
->andWhere("ttr.tipo_tramite_id = :tramite")
->setParameter("tramite", 1)
->setParameter('activo', true);
}
But that solution cause this error:
[Semantical Error] line 0, col 121 near 'tipo_tramite_id': Error:
Class AppBundle\Entity\TipoTramite has no field or
association named tipo_tramite_id
I tried this one also (as suggested per user here):
->andWhere("ttr.tipoTramites = :tramite")
But the errors turns into this one:
[Semantical Error] line 0, col 120 near 'tipoTramites': Error: Invalid
PathExpression. StateFieldPathExpression or
SingleValuedAssociationField expected
Also I've tried this other solution:
->andWhere("tr.id = :tramite")
But this one doesn't return the right values. I read something about Closures on the entity field type but has no idea in how to implement on this scenario. The other idea comes to me is use a DQL and a preparement statement but I thin this can't be used at form level, so I'm out of ideas, then how I can get those values? How I should establish the relation between this ManyToMany entities?
When you create a ManyToMany relationship in your entity, Doctrine will generate the third table as mediator between those two entities (named in #ORM\JoinTable) with two fields (defined in joinColumns). You do not have direct access to the fields or columns in the third table but they all will be handled by Doctrine in your DQL.
This means in your DQL you need to just set the joint table id in your where clause not the real field name and Doctrine will produce the proper SQL:
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('tr')
->where('tr.activo = :activo')
->leftJoin('tr.tipoTramites', 'ttr')
->andWhere("ttr.id = :tramite")
->setParameter("tramite", 1)
->setParameter('activo', true);
}
This will produce the proper SQL.
The only tip is you do not have access to the generated fields of third table in you DQL, but it will be handled by Doctrine and you can use the join table id instead

Doctrine ORM : Calculated related entity count in one shot

I've a User entity and a Product entity.
class User{
/*
* #ORM\OneToMany(targetEntity="Product", mappedBy="User")
*/
private $Products;
}
class Product{
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="Products")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $User;
}
Now I'm trying to display a html table of users, but I want to show each user's product count too.
By using following code I'm able to obtain the users objects.
$qb = $this->_em->createQueryBuilder();
$qb->select('usr')
->from('User', 'usr');
$query = $qb->getQuery();
But I don't know how to get the products count in one shot. Any help?
First, you should really create a repository class for your entities if you want to create custom queries. Then you can simply run that query by injecting the entity repository as a service wherever you need it and then running the query method.
Second, you need to return a result from a doctrine query to retrieve anything from the database. If you want to determine the count of the objects returned, simply do this:
$qb = $this->_em->createQueryBuilder();
$qb->select('usr')
->from('User', 'usr');
$query = $qb->getQuery();
$count = count($query->getResult());
A doctrine query will return an array of objects matching your query. If you just want to return a count of the matching records, try something like this:
$qb = $this->_em->createQueryBuilder();
$qb->select('count(id)')
->from('User', 'usr');
$query = $qb->getQuery();
$count = $query->getSingleScalarResult();
Or to just get a count of Product objects for that user, from within the User repository class:
$qb = $this->_em->createQueryBuilder('usr');
$qb->select('count(p.id)')
->from('usr.Products', 'p');
return $qb->getQuery()->getSingleScalarResult();

Resources