Symfony 4 query elements from joined table if they exist - php

I have two tables gifts and gift_tags how can I select all gifts with tags that are not present in $avoidTags array only if gift has tags. The way my query works now it selects only the gifts that have at least one tag in gift_tags table and it is not in $avoidTags array, but I need also those that have no tags at all.
$response = $qb
->select('g, tags')
->leftJoin('g.tags', 'tags')
->andwhere($qb->expr()->notin("tags.name", ":avoidTags"))
->setParameters(new ArrayCollection([
new Parameter('avoidTags', $avoidTags),
]))
->getQuery()
->getResult();

With the mysql, it can do with this query
SELECT
gift.*, tag.*
FROM
gift
LEFT JOIN tag ON gift.id = tag.gift_id
WHERE gift.id NOT IN (
SELECT g.id FROM gift AS g LEFT JOIN tag AS t ON g.id = t.gift_id WHERE t.name IN ('test', 'test2')
)
So with the doctrine QB it maybe something like this
$subQb = $this->_em->createQueryBuilder()
->select('gift.id')
->leftJoin('gift.tags', 'tags')
->where($qb->expr()->orX(
$qb->expr()->in("tags.name", ":avoidTags")),
))
->getQuery();
$response = $qb
->select('g, tags')
->leftJoin('g.tags', 't')
->where($qb->expr()->notin("g.id", $subQb->getDql())))
->setParameters(new ArrayCollection([
new Parameter('avoidTags', $avoidTags),
]))
->getQuery()
->getResult();

Related

Join same table to get other value in symfony 6

someone know how to join same table in symfony 6 doctrine to get different results?
I tried something like that
public function findAllStats(){
return $this->createQueryBuilder('a')
->select('count(a.id) as count, a.countryCode, count(acc) as all_accounts, count(ao) as all_online_today')
->leftJoin('a.accounts', 'acc', 'with', "acc.owner = a.id")
->andWhere('a.countryCode is not null')
->groupBy('a.countryCode')
->orderBy('count(a.id)', 'ASC')
->having('count(a.id) > 2')
->setParameter('today' , (new \DateTime())->setTime(0,0,0))
->getQuery()
->getScalarResult();
}
i just want to get next results and its okay:
country_code,
count of all users,
count of all accounts (relation)
but i dont know how to add:
count of all users updated today
i tried this:
public function findAllStats(){
return $this->createQueryBuilder('a')
->select('count(a.id) as count, a.countryCode, count(acc) as all_accounts, count(ao) as all_online_today')
->leftJoin('a.accounts', 'acc', 'with', "acc.owner = a.id")
->andWhere('a.countryCode is not null')
->groupBy('a.countryCode')
->orderBy('count(a.id)', 'ASC')
->having('count(a.id) > 2')
->setParameter('today' , (new \DateTime())->setTime(0,0,0))
->getQuery()
->getScalarResult();
}
but it doesn't works. Some solutions to join same table with different Where criteria?
but it doesn't works. Some solutions to join same table with different Where criteria?
Okay i found the solution. I used Class of entity and left join but is that a correct way?
->leftJoin(User::Class, 'ao', 'with', "ao.id = a.id AND ao.updatedAt >= :today")

How to select everything in column with Doctrine and Symfony

I'm trying to build small query with QueryBuilder where category parameter that can be passed to query or not.
$category = 'Boots';
If not I'd like to select all categories.
I use "where" for this. In mySql you can use "WHERE column = column" and everything is selected. I tried this with the builder but it doesn't work:
$qb = $this->createQueryBuilder('p')
->select("p.id, p.price, stock.qty, p.images, category.name,
p.model, s.size AS size, c.name AS color,
b.name AS brand, category.name AS catName")
->innerJoin('p.stocks', 'stock')
->innerJoin('p.brand', 'b')
->innerJoin('stock.size','s')
->innerJoin('stock.color', 'c')
->innerJoin('p.category', 'category')
->where('category.name = :category')
->andWhere('s.size IN (:sizes)')
->andWhere('b.name IN (:brands)')
->andWhere('p.price > :priceFrom')
->andWhere('p.price < :priceTo')
->setParameter('category', 'category.name') /// ??? the problem is here
->setParameter('sizes', $sizes, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
->setParameter('brands', $brands, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
->setParameter('priceFrom', $priceFrom)
->setParameter('priceTo', $priceTo)
->groupBy('p.model')
->getQuery()
->getResult();
Check the lines:
->where('category.name = :category')
->setParameter('category', 'category.name') /// ??? the problem is here
When i try to set column to column it doesn't work. I tried also diferrent combinations like, but no results. Any advice? Thanks

Order by count of relational field

I have the following relations:
Member one-to-many Product
Product many-to-one Member
This is the query that I have that works:
$qb = $this->createQueryBuilder('m');
$qb
->where('m.Authority = :Authority')
->setParameter('Authority', Authority::CREATOR)
->innerJoin('m.Product', 'p')
->select('COUNT(p) AS HIDDEN item_count', 'm')
->groupBy('m')
->orderBy("item_count", "ASC");
However when I add additional parameters for product status
$qb = $this->createQueryBuilder('m');
$qb
->where('m.Authority = :Authority')
->setParameter('Authority', Authority::CREATOR)
->andWhere('p.Status = :Status')
->setParameter('Status', 1);
->innerJoin('m.Product', 'p')
->select('COUNT(p) AS HIDDEN item_count', 'm', 'p')
->groupBy('p')
->orderBy("item_count", "ASC");
The order by doesn't happen anymore. I dumped the value for item_count and it's alway 1. Has anyone encountered the same problem? The goal here is to get a list of Members with Products with status = 1 ordered by the number of Products.
Edit:
If I change groupBy('p') to groupBy('m'), it will only load one related Product for each Member
For anyone who struggled with the same problem, this is how I did it:
$qb = $this->createQueryBuilder('m');
$qb
->where('m.Authority = :Authority')
->setParameter('Authority', Authority::CREATOR)
->andWhere('p.Status = :Status')
->setParameter('Status', 1);
->select('p, m')
->addSelect('(SELECT COUNT(DISTINCT p1)
FROM Eccube\Entity\Member m1
INNER JOIN Eccube\Entity\Product p1
WHERE m1.Authority = ' . Authority::CREATOR . ' AND p1.Status = 1 AND p1.Creator = m.id
) AS hidden item_count')
->innerJoin('m.Product', 'p')
->groupBy('p')
->orderBy("item_count", "ASC");
It works but I don't understand why this is p1.Creator = m.id ? If I use m1.id it will just sum up the item count.
Edit: Added updated code after Jakumi's comment regarding the join. Even though both code works, the second one makes more sense.
$qb = $this->createQueryBuilder('m');
$qb
->where('m.Authority = :Authority')
->setParameter('Authority', Authority::CREATOR)
->andWhere('p.Status = :Status')
->setParameter('Status', 1);
->select('p, m')
->addSelect('(SELECT COUNT(DISTINCT p1)
FROM Eccube\Entity\Member m1
INNER JOIN m1.Product p1
WHERE m1.Authority = ' . Authority::CREATOR . ' AND p1.Status = 1 AND p1.Creator = m
) AS hidden item_count')
->innerJoin('m.Product', 'p')
->groupBy('p')
->orderBy("item_count", "ASC");

Doctrine2 - double left join query issue

I am using Symfony v3.4 branch with Doctrine.
I am having trouble translating SQL query to Doctrine ORM query.
I have 3 tables.
Shop
Firm
User
User --> 1:1 --> Firm --> 1:1 --> Shop
(Symfony developer tool bar reports that associations in tables are made correctly).
I want to get Shop data that corresponds to cretain User in one query.
My SQL, that get a result:
SELECT *
FROM mp2_fos_user as u
LEFT JOIN mp2_firm AS f ON u.id = f.firmUserId
LEFT JOIN mp2_shop AS s ON f.id = s.shopFirmId
WHERE u.id = 1
My Doctrine ORM query
$query = $em->createQueryBuilder()
->select('u, f, s')
->from('App:User', 'u')
->leftJoin('u.userFirm WITH u.id = f.firmUserId', 'f')
->leftJoin('f.firmShop WITH f.id = s.shopFirmId', 's')
->where('u.id = :user_id')
->setParameter('user_id', $user_id)
->getQuery();
at the moment running the code results in an error
[Syntax Error] line 0, col 57: Error: Expected end of string, got 'u'
What would be best practice for my issue?
Help would be much appreciated,
Thank you!
UPDATE
tried:
$query = $em->createQueryBuilder()
->select('s.id')
->from('App:User', 'u')
->leftJoin('u.userFirm WITH f.firmUser = u', 'f')
->leftJoin('f.firmShop WITH s.shopFirm = f', 's')
->where('u.id = :user_id')
->setParameter('user_id', $user_id)
->getQuery();
got [Syntax Error] line 0, col 54: Error: Expected end of string, got 'f'
There is no need to use WITH clause if you have defined mapping in your entities, WITH clause is used when you want to join your entities with additional matching criteria
class User
{
/**
* #ORM\YourRelationShipNature(targetEntity="App\Entity\Firm", mappedBy="user")
*/
private $userFirm;
}
class Firm
{
/**
* #ORM\YourRelationShipNature(targetEntity="App\Entity\Shop", mappedBy="firm")
*/
private $firmShop;
}
class Shop
{
//.....
}
And then your could simple use properties to join your entites
$query = $em->createQueryBuilder()
->select('u, f, s')
->from('App:User', 'u')
->leftJoin('u.userFirm', 'f')
->leftJoin('f.firmShop', 's')
->where('u.id = :user_id')
->setParameter('user_id', $user_id)
->getQuery();
I was thinking of something more along the lines of this (assuming the entity names are correct):
$query = $em->createQueryBuilder()
->select('u, f, s')
->from('App:User', 'u')
->leftJoin('App:UserFirm f WITH f.firmUser = u')
->leftJoin('App:FirmShop s WITH s.shopFirm = f')
->where('u.id = :user_id')
->setParameter('user_id', $user_id)
->getQuery();

How to implement subqueries in Symfony2 with Doctrine?

I need to count the number of items returned in the subquery. If I write the subquery how DQL - all good, but if I try to build a query via QueryBuilder - I get an error.
Subquery DQL:
$qb3 = $this->createQueryBuilder('c')
->select('COUNT(c.id)')
->where('c.id IN (SELECT cl.id FROM Acme\AppBundle\Entity\ClassC cl INNER JOIN Acme\AppBundle\Entity\ClassP p WHERE p.var1 = :var1 AND p.var2 = cl.id GROUP BY cl.id)')
->setParameter('var1', $var);
Subquery via QueryBuilder:
$qb = $this->createQueryBuilder('c');
$qb->select('COUNT(c.id)')
->where(
$qb->expr()->in(
'c.id',
$this->createQueryBuilder('cl')
->select('cl.id')
->innerJoin('Acme\AppBundle\Entity\ClassP', 'p')
->where('p.var1 = :var1')
->setParameter('var1', $var)
->andWhere('p.var2 = cl.id')
->groupBy('cl.id')
->getDQL()
)
);
Both versions return the same DQL.
Error:
screen
Try to move setParameter() to main level of query.
$qb = $this->createQueryBuilder('c');
$qb->select('COUNT(c.id)')
->where(
$qb->expr()->in(
'c.id',
$this->createQueryBuilder('cl')
->select('cl.id')
->innerJoin('Acme\AppBundle\Entity\ClassP', 'p')
->where('p.var1 = :var1')
->andWhere('p.var2 = cl.id')
->groupBy('cl.id')
->getDQL()
)
)
->setParameter('var1', $var);

Categories