Sorting the most relation with Doctrine - php

Sorting the most relation with Doctrine?
Relation
#[ORM\ManyToOne(inversedBy: 'users')]
#[ORM\JoinColumn(nullable: false)]
private ?University $university = null;
My repository code ( Doesn't sort correctly )
public function sortPopularChats(): array
{
return $this->createQueryBuilder('u')
->orderBy('u.university', 'DESC')
->groupBy('u.university')
->setMaxResults(5)
->getQuery()
->getResult()
;
}
My user table
|id|university_id|
|1|100610385|...
|2|106952005|...
|5|100610385|...
|11|108410557|...
|6|100610385|...
|7|106952005|...
|4|100610385|...
|9|106952005|...
|10|100610385|...
Sorting should be like this
100610385
106952005
108410557
...
...

You need a count expression in order to be able to use it as the ordering field, but doing that it'll return a ScalarResult, with both the count and the object. To prevent that, you can use the HIDDEN keyword (scroll down or search for it) so only the University entities are returned:
public function sortPopularChats(): array
{
return $this->createQueryBuilder('e')
->leftJoin('e.university', 'u')
->addSelect('u, count(u) AS HIDDEN uniCount')
->orderBy('uniCount', 'ASC')
->groupBy('u.id')
->setMaxResults(5)
->getQuery()
->getResult()
;
}

Related

Find element in array data using createQueryBuilder

I have a table ( shops) in witch I store data like this: ["bsd1234","qwe9876"] in a field named products and I want to get the shops objects that contain a given product using createQueryBuilder().
It should look like this, but I can't find the solution:
public function findByProducts($value)
{
return $this->createQueryBuilder('s')
->andWhere('s.products = :val')
->setParameter('val', $value)
->orderBy('s.id', 'ASC')
->getQuery()
->getResult()
;
}
Can you help mw with that?

Error: 'c' is used outside the scope of its declaration

An application has a page of statistics representing dozens of calculations. To avoid duplicating code in a repository the error
Error: 'c' is used outside the scope of its declaration
occurs when attempting to insert DQL with conditions into a QueryBuilder.
The basic entities include Household and Contact. Calculations are based on contact date range, site (location of contact), and type (type of contact). There is a service that creates an array of where clauses and query parameters, as will be evident in the code below.
I know the calculation works if all the code occurs in a single function. It seems the problem arises from the join with the Contact entity and its necessary constraints. Can DRY be accomplished in this scenario?
All of the following appear in the Household entity's repository.
The DQL is:
private function reportHousehold($criteria)
{
return $this->createQueryBuilder('i')
->select('i.id')
->join('TruckeeProjectmanaBundle:Contact', 'c', 'WITH',
'c.household = i')
->where($criteria['betweenWhereClause'])
->andWhere($criteria['siteWhereClause'])
->andWhere($criteria['contactWhereClause'])
->getDQL()
;
}
Example of $criteria: $criteria['betweenWhereClause'] = 'c.contactDate BETWEEN :startDate AND :endDate'
One of the calculations on Household:
public function res($criteria)
{
$parameters = array_merge(
$criteria['betweenParameters'], $criteria['siteParameters'],
$criteria['startParameters'], $criteria['startParameters'],
$criteria['contactParameters']);
$qb = $this->getEntityManager()->createQueryBuilder();
return $this->getEntityManager()->createQueryBuilder()
->select('h.id, 12*(YEAR(:startDate) - h.arrivalyear) + (MONTH(:startDate) - h.arrivalmonth) Mos')
->from('TruckeeProjectmanaBundle:Household', 'h')
->distinct()
//DQL inserted here:
->where($qb->expr()->in('h.id', $this->reportHousehold($criteria)))
->andWhere($qb->expr()->isNotNull('h.arrivalyear'))
->andWhere($qb->expr()->isNotNull('h.arrivalmonth'))
->andWhere($criteria['startWhereClause'])
->setParameters($parameters)
->getQuery()->getResult()
;
}
You're either missing getRepository() or from()
Try this (my prefered choice) :
private function reportHousehold($criteria) {
return $this->getEntityManager
->createQueryBuilder()
->select("i.id")
->from(YourEntity::class, "i")
->join("TruckeeProjectmanaBundle:Contact", "c", "WITH", "c.household=i.id")
->where($criteria['betweenWhereClause'])
->andWhere($criteria['siteWhereClause'])
->andWhere($criteria['contactWhereClause'])
->getQuery()
->execute();
}
Or this
private function reportHousehold($criteria) {
return $this->getEntityManager
->getRepository(YourEntity::class)
->createQueryBuilder("i")
->select("i.id")
->join("TruckeeProjectmanaBundle:Contact", "c", "WITH", "c.household=i.id")
->where($criteria['betweenWhereClause'])
->andWhere($criteria['siteWhereClause'])
->andWhere($criteria['contactWhereClause'])
->getQuery()
->execute();
}
Careful, I'm assuming you're on Symfony 3 or above.
If not, replace YourEntity::class by Symfony 2 syntax which is "YourBundle:YourEntity"
In a sense Preciel is correct: the solution does require the use of $this->getEntityManager()->createQueryBuilder(). Instead of injecting DQL as a subquery, the trick is to return an array of ids and use the array in an IN clause. The effect is to remove any consideration of entities other than the Household entity from the calculation. Here's the result:
public function res($criteria)
{
$parameters = array_merge($criteria['startParameters'], $criteria['startParameters'], ['hArray' => $this->reportHousehold($criteria)]);
$qb = $this->getEntityManager()->createQueryBuilder();
return $this->getEntityManager()->createQueryBuilder()
->select('h.id, 12*(YEAR(:startDate) - h.arrivalyear) + (MONTH(:startDate) - h.arrivalmonth) Mos')
->from('TruckeeProjectmanaBundle:Household', 'h')
->distinct()
->where('h.id IN (:hArray)')
->andWhere($qb->expr()->isNotNull('h.arrivalyear'))
->andWhere($qb->expr()->isNotNull('h.arrivalmonth'))
->setParameters($parameters)
->getQuery()->getResult()
;
}
private function reportHousehold($criteria)
{
$parameters = array_merge($criteria['betweenParameters'], $criteria['siteParameters'], $criteria['contactParameters']);
return $this->createQueryBuilder('i')
->select('i.id')
->join('TruckeeProjectmanaBundle:Contact', 'c', 'WITH', 'c.household = i')
->where($criteria['betweenWhereClause'])
->andWhere($criteria['siteWhereClause'])
->andWhere($criteria['contactWhereClause'])
->setParameters($parameters)
->getQuery()->getResult()
;
}

Symfony Order entities by field OneToMany

Who knows how to solved this simple question?
I have entity project with field likedUsers and in twig count up this field but I want order projects by this count up (DESC) - first who have more likedUsers. How to do it? In query builder or in twig create filter?Help with doctrine I know count
"likes_user" => count($this->getLikedUsers()->getValues())
how to sort my all projects from this field?
or how its solved with query builder?
something like that, but this is not work:
public function getProjects()
{
$qb = $this->getEntityManager()->createQueryBuilder('d');
$qb
->select('d')
->from('AppBundle:Project', 'd')
->where('d.confirm = :identifier')
->setParameter('identifier', 'approved')
->orderBy('COUNT(d.likedUsers)', 'DESC')
->getQuery()
->getResult()
;
$query = $qb->getQuery();
$results = $query->getResult();
return $results;
}
entity:
/**
* Project
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="AppBundle\Entity\ProjectRepository")
*/
class Project implements \JsonSerializable
{
/**
* #var Collection
*
* #ORM\OneToMany(targetEntity="AppBundle\Entity\User", mappedBy="likedProjects")
*/
private $likedUsers;
{% for project in projects %}
<div>LIked: <span>{{ project.likedUsers|length|number_format(0, '.', ' ') }}</span></div>
{% endfor %}
I think maybe like that:
{% for project in projects.likedUsers|length|sort %}
but not effect
maybe who knows? How array projects sort by count of field LikedUser. I don’t know how do this. Query builder or twig extension or usort..
IMHO, this seems like a job for PHP instead of Doctrine. Not sure if t could be achieved by Doctrine and, if possible, what would be an impact.
One way to do this is usort().
$projects = ...;
usort($projects, function($p1, $p2){
// Both $p1 and $p2 are instance of Project
// Assuming that `getLikedUsers()` return Doctrine `Collection`...
return count($p1->getLikedUsers()) > count($p2->getLikedUsers());
});
usort takes an array and in each pass offers two items (two projects in your case) for you to decide which one is "greater". In your case, the project with more likes is definitely "greater", right?
Hope this helps...
I solved with query builder. And I add only project who have like user - user live in some city no all city
public function getProject()
{
$qb = $this->getEntityManager()->createQueryBuilder('d');
$qb
->select('d')
->from('AppBundle:Project', 'd')
->addSelect('COUNT(m.id) as nMethods')
->join('d.likedUsers', 'm')
->join('m.location', 'l')
->where('l.city = :identifier')
->setParameter('identifier', 'someCity')
->groupBy('d.id')
->orderBy("nMethods", 'DESC')
->getQuery()
->getResult()
;
$query = $qb->getQuery();
$results = $query->getResult();
return $results;
}

Order attribute of an object in Symfony

I would like to reorder the attribute (COMMENTS) of my object (instance of ARTICLE) after I retrieve it from the DBB. Is this possible?
My object is ARTICLE and it is linked to COMMENTS (which is defined as a collection in entity article)
I know I can order through the repository but the order of my comments depend on many conditions, some not available through the DB.
Condition exemple:
I want at the top the comment whose attribute show_first are set to true whatever their score, and then the other comments ordered depending of their score.
You could add a hidden field to you query that sorting things in the order that you wanted so that you don't need to process the complete ArrayCollection to sort.
public function findByArticleInOrderOfState()
{
return $this->createQueryBuilder('c')
->select('c')
->addSelect('
CASE
WHEN c.state = :state_new THEN 1
WHEN c.state = :state_viewed THEN 2
WHEN c.state = :state_deleted THEN 3
ELSE 4
END AS HIDDEN order_by
')
->setParameter('state_new', 'new')
->setParameter('state_viewed', 'viewed')
->setParameter('state_deleted', 'deleted')
->orderBy('order_by', 'ASC')
->addOrderBy('c.createdAt', 'ASC')
->getQuery()
->getResults();
}
This would create a hidden field order_by and set that depending on the current state of that object, then it would order by that hidden field and then createdAt.
It doesn't really make sense to order comments like that but it does show how you could do it. With a little more info on the actual use case I would (hopefully) be able to make work a bit closer to your specific needs.
Update
In your case when you have show_first == 'yes'|'no' you could do the following..
public function findByArticleInOrderOfState()
{
return $this->createQueryBuilder('c')
->select('c')
->addSelect('
CASE
WHEN c.show_first = :show_first THEN 1
ELSE 2
END AS HIDDEN order_by
')
->setParameter('show_first', 'yes')
->orderBy('order_by', 'ASC')
->addOrderBy('c.createdAt', 'ASC')
->getQuery()
->getResults();
}
Set the getter of comments (getComments()) in your Article entity to get the comments in the order you want.
public function getComments(){
$iterator = $comments->getIterator();
$iterator->uasort(function ($a, $b) {
// change getProperty() with the field you want to order on
return ($a->getProperty() < $b->getProperty()) ? -1 : 1;
});
$comments= new ArrayCollection(iterator_to_array($iterator));
return $comments;
}
For more Infos visit this post "usort" a Doctrine\Common\Collections\ArrayCollection?
For simple ordering of associations, you can use Doctrine annotations.
/**
* #ORM\OneToMany(targetEntity="Comment", mappedBy="article")
* #ORM\OrderBy({"show_first" = "ASC", "score" = "DESC"})
*/
private $comments;
https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/tutorials/ordered-associations.html
The following possible within an entity object
public function getCommentsActiveLast3()
{
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->eq('status', Comment::STATUS_PUBLISHED));
$criteria->setMaxResults(3);
if ($this->comments) {
return $this->comments->matching($criteria);
}
}

Get all entities ordered with Doctrine query builder

I'm getting a little crazy with this. I have a PhoneCodes entity and I simply want to retrieve all entities ordered by a field so no where condition but I tried to achieve this by many ways and not working. Currently I have this:
$phonecodes = $this->getDoctrine()
->getRepository('AcmeDemoBundle:PhoneCodes')
->createQueryBuilder('p')
->orderBy('p.length', 'ASC')
->getQuery()
->getResult();
What's the way to do this? Thanks.
Your code should be something like this:
$phonecodes = $this->getEntityManager()
->createQueryBuilder()
->select("p")
->from("AcmeDemoBundle:PhoneCodes", "p")
->orderBy("p.length", "ASC")
->getQuery()
->getResult()
If you're in a controller just do this:
$phonecodes = $em->getRepository('AcmeDemoBundle:PhoneCodes')->findBy(
array(),//conditions, none in this case
array(//orderBy, multiple possible
"length"=>"asc"
)
);
This way you don't need to write a custom repository function.
If you wan't to create it as a repository function (e.g. in PhoneCodesRepository.php) do it that way:
/**
* Returns all phoneCodes hydrated to objects ordered by length
* #param string $order - ASC | DESC
* #return \Doctrine\Common\Collections\Collection
*/
function findAllOrderedByLength($order="ASC")
{
$qb = $this->createQueryBuilder("p");
$qb->orderBy("p.length", $order);
return $qb->getQuery()->getResult();
}
http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes

Categories