Order joined table with Doctrine - php

I wrote a query with doctrine where I have joined fruits and vitamins table.
I have sorted vitamins by name ASC but I need to do the same thing with joined table.
I tried
addOrderBy()
, but no luck..
Note: 'c' is Vitamins table.
Everything is returned as it should except fruits are returned with no order..
My code:
$queryBuilder = $this->createQueryBuilder('c')
->select('c', 'ct.name AS fruitName', 'ct.id AS fruitId')
->join('App\Entity\Fruits', 'ct', Expr\Join::WITH, 'ct.id = c.fruitName')
->orderBy('c.name');
$fruits = $queryBuilder->getQuery()->getResult();
$structure = [];
foreach ($fruits as $fruit) {
$structure[$fruit['fruitName']][] = $fruit[0];
}
return $structure;

Try one of these:
Option 1:
$qb->orderBy('c.name ASC, ct.name ASC');
Option 2:
$qb->addOrderBy('c.name', 'ASC')
->addOrderBy('ct.name', 'ASC')

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

Eloquent wherein with join multiple tables

I have 4 tables, items, listings, catitem_item, and item_listing.
items and listing is many to many relationship.
items and catitems is also many to many relationship.
catitems contains list of item's categories.
listings is like location where items located.
example listing shop A can have item chair and item chair have multiple catitem categories.
My goal is to get items which under list of categories such as category 1 AND 2 AND 3 ($cats) and with listing information where this item located.
So if there are 6 listings for chair, it will return 6 chair results.
This is the query I have so far.
$items = DB::table('items')
->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
->join('item_listing', 'item_listing.item_id', '=', 'items.id')
->join('listings', 'item_listing.listing_id', '=', 'listings.id')
->whereIn('catitem_item.catitem_id', $cats)
//->groupBy('items.id')
//->having(DB::raw('count(*)'), '=', count($cats))
->select('items.id', 'items.name', 'items.price', 'items.slug', 'item_listing.listing_id', 'listings.name as listing_name', 'listings.slug as listing_slug')
->get();
Note that the way you are trying to do it, you might get multiple rows per item (once per related listing). A better way would be to have an array of listings per item.
If you use eloquent models and you have setup the relations correctly, you could try the following:
$cats = [1, 2, 3];
$query = Item::with('listings');
foreach ($cats as $cat) {
$query->whereHas('catitems', function($q) use($cat) {
$q->where('id', $cat);
});
}
$items = $query->get();
Now every item shoud have a listings property. For example for the first item you can access the listings the following way:
$item1 = $items[0];
$listings1 = $item1->listings;
Note that whereHas() will probably create a correlated EXISTS subquery for every entry in the $cats array. If that is to slow, you can use a JOIN query like:
$items = Item::with('listings')
->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
->whereIn('catitem_item.catitem_id', $cats)
->groupBy('items.id')
->having(DB::raw('count(*)'), '=', count($cats))
->select('items.*')
->get();
If you don't use eloquent, you can also do the "eager loading" yourself.
$items = DB::table('items')
->join('catitem_item', 'catitem_item.item_id', '=', 'items.id')
->whereIn('catitem_item.catitem_id', $cats)
->groupBy('items.id')
->having(DB::raw('count(*)'), '=', count($cats))
->select('items.*')
->get()
->keyBy('id');
foreach ($items as $item) {
$item->listings = [];
}
$itemIds = $items->pluck('id');
$listings = DB::table('listings')
->join('item_listing', 'item_listing.listing_id', '=', 'listings.id')
->whereIn('item_listing.item_id', $itemIds)
->groupBy('listings.id')
->select('listings.*', DB::raw('group_concat(item_listing.item_id) as item_ids'))
->get();
foreach ($listings as $listing) {
$itemIds = explode(',', $listing->item_ids);
foreach ($itemIds as $itemId) {
$items[$itemId]->listings[] = $listing;
}
$listing->forget('item_ids');
}

Symfony2 index of an object sorted by DQL

Hi I've done a simple query for a ranking mechanism with the query builder.
$result = $qb
->select('u')
->where('u.status = 1')
->from('PGMainBundle:User', 'u')
->groupBy('u.id')
->addSelect('COUNT(c.id) as HIDDEN nChallenges')
->leftJoin('u.challenges', 'c', 'WITH', 'c.closed = 1' )
->add('orderBy','u.points DESC, nChallenges DESC')
->orderBy('u.points', 'DESC')
->addOrderBy('nChallenges', 'DESC')
->setFirstResult($offset*50)
->setMaxResults(50)
->getQuery()
->getResult();
Now while my ranking mechanism works fine, I'd like to check what loop.index a user with an $id has.
Said this, I don't want to use a foreach loop on the result to do so.
Is there a more optimal way just to return the "position" in the ranking ?
Possibly using the query builder ?
The result should be an array collection so you can get the index of a given element like this :
$result->indexOf($yourelement)
Else if the keys are not in order, but are the id of the entities :
$keys = $result->getKeys();
$id = $yourElement->getId();
$position = array_search($id, $keys);

How to sort a Laravel query builder result by multiple columns?

I want to sort multiple columns in Laravel 4 by using the method orderBy() in Laravel Eloquent. The query will be generated using Eloquent like this:
SELECT *
FROM mytable
ORDER BY
coloumn1 DESC, coloumn2 ASC
How can I do this?
Simply invoke orderBy() as many times as you need it. For instance:
User::orderBy('name', 'DESC')
->orderBy('email', 'ASC')
->get();
Produces the following query:
SELECT * FROM `users` ORDER BY `name` DESC, `email` ASC
You can do as #rmobis has specified in his answer, [Adding something more into it]
Using order by twice:
MyTable::orderBy('coloumn1', 'DESC')
->orderBy('coloumn2', 'ASC')
->get();
and the second way to do it is,
Using raw order by:
MyTable::orderByRaw("coloumn1 DESC, coloumn2 ASC");
->get();
Both will produce same query as follow,
SELECT * FROM `my_tables` ORDER BY `coloumn1` DESC, `coloumn2` ASC
As #rmobis specified in comment of first answer you can pass like an array to order by column like this,
$myTable->orders = array(
array('column' => 'coloumn1', 'direction' => 'desc'),
array('column' => 'coloumn2', 'direction' => 'asc')
);
one more way to do it is iterate in loop,
$query = DB::table('my_tables');
foreach ($request->get('order_by_columns') as $column => $direction) {
$query->orderBy($column, $direction);
}
$results = $query->get();
Hope it helps :)
Use order by like this:
return User::orderBy('name', 'DESC')
->orderBy('surname', 'DESC')
->orderBy('email', 'DESC')
...
->get();
Here's another dodge that I came up with for my base repository class where I needed to order by an arbitrary number of columns:
public function findAll(array $where = [], array $with = [], array $orderBy = [], int $limit = 10)
{
$result = $this->model->with($with);
$dataSet = $result->where($where)
// Conditionally use $orderBy if not empty
->when(!empty($orderBy), function ($query) use ($orderBy) {
// Break $orderBy into pairs
$pairs = array_chunk($orderBy, 2);
// Iterate over the pairs
foreach ($pairs as $pair) {
// Use the 'splat' to turn the pair into two arguments
$query->orderBy(...$pair);
}
})
->paginate($limit)
->appends(Input::except('page'));
return $dataSet;
}
Now, you can make your call like this:
$allUsers = $userRepository->findAll([], [], ['name', 'DESC', 'email', 'ASC'], 100);
$this->data['user_posts'] = User_posts::with(['likes', 'comments' => function($query) { $query->orderBy('created_at', 'DESC'); }])->where('status', 1)->orderBy('created_at', 'DESC')->get();

Categories