Preserve the initial order of array in Symfony2 Doctrine findBy() - php

I have an array ($newsList) of IDs with the following values: 4,2,1,3.
I'm trying to get some data from the database from entity:
$news=$this->getDoctrine()->getRepository('Bundle:News')->findBy(array('id' => $newsList));
$newsList array represents real IDs from the News entity.
But when I do:
foreach($news as $n){
$n->getId();
}
IDs are in order: 1,2,3,4.
How can I preserve the order from beginning in foreach?

You can't.
It's how it's returned from DB. If you won't specify ORDER BY clause in query, database will return rows as they are in storage, and this is usually the same as id ASC.
You should sort them on your own in PHP.

You can use usort and the spaceship operator:
$newsList = [4, 2, 1, 3];
$news = $this->getDoctrine()->getRepository(News::class)->findBy(['id' => $newsList]);
$order = array_flip($newsList);
usort($news, function($a, $b) use ($order) {
return $order[$a->getId()] <=> $order[$b->getId()];
});
// $news is now ordered by id 4,2,1,3

As you are doing a global query, you can just order your results by a given property, and a given sort order, so as pointed by the previous answer, you can't.
To have your results ordered exactly as the array you given, you can do this:
$newsList = [3, 1, 4, 2];
$newsRepo = $this->getDoctrine()->getRepository('Bundle:News');
foreach ($newsList as $id) {
$new = $newsRepo->findOneBy['id' => $id];
if ($new !== null) {
$news[] = $new;
}
}
Like this, your results are ordered exactly like $newsList, e.g:
foreach ($news as $n) {
print $n->getId();
}
// Output: 3 1 4 2

IMO the best solution is to use field function to get proper news order:
$ids = [4, 1, 2, 3];
$news = $this->getDoctrine()->getRepository('Bundle:News')->createQueryBuilder('n')
->select('n, field(n.id, :ids) as HIDDEN field')
->where("n.id IN (:ids)")
->setParameter('ids', $ids )
->orderBy(field)
->getQuery()
->getResult();
Note: this solution require custom field function that can be found here.

Try this:
$news = $this->getDoctrine()->getRepository('Bundle:News')->createQueryBuilder('n')
->where("n.id IN(:Ids)")
->setParameter('Ids', $newsList ) // $newsList = array(1,2,3,4,...)
->getQuery()
->getResult();

I don't know if you can actually get them sorted from the returning query results, but you can do either of these options:
Do a foreach loop and execute 'findByOne' for each result:
foreach($newsList as $id) {
$news[]=$this->getDoctrine()->getRepository('Bundle:News')->findBy(array('id' => $id));
}
Order the results of the query afterwards:
$news=$this->getDoctrine()->getRepository('Bundle:News')->findBy(array('id' => $newsList));
foreach($newsList as $id) {
$sorted_news[] = $news[$id];
}

Related

Is there a way to loop query builder through orWhereIn parameters one by one?

I was wondering if there's a way to loop ->OrWhereIn('parent_id', $data1,2,3,4,5)?
$data= data::query()
->where('parent_id', $this->id)
->orWhereIn('parent_id', $data1)
->orWhereIn('parent_id', $data2)
->orWhereIn('parent_id', $data3)
->orWhereIn('parent_id', $data4);
Maybe you could something like this:
->orWhereIn('parent_id', [$data1, $data2, $data3, $data4])
Provided all of these are not subarrays. If they are merge them into a single array before trying this.
You can use just whereIn function to achieve that result and instead of looping queries, just loop the array you pass whereIn function as second parameter.
$parent_ids = [];
foreach($some_data as $data) {
// [add ids in parent_ids here]
}
$data= data::query()->whereIn('parent_id', $parent_ids);
Or if you want to loop in query builder you can use nested where:
$parent_ids = [1, 2, 3, 4, $data];
$data= data::query()
->where(function($q) use ($parent_ids) {
foreach($parent_ids as $id) {
$q->orWhere('parent_id', $id);
}
});
Result SQL:
SELECT * FROM table WHERE (parent_id = 1 OR parent_id = 2 OR parent_id = 3 ... );

Sort foreach loop result

I want to sort it by $distance base in foreach loop in my VIEWS.. so heres my code in Models
$db = $this->getDbo();
$query = $db->getQuery(true)
->select('*')
->from('#__load');
$db->setQuery($query);
$db->query();
$rows = $db->loadObjectList();
return $db->loadObjectList();
This is the code in my View where i want to sort it by distance
foreach ($this->items as $i => $item) {
$distance = $item->result1 * $item->result2
sort($distance)
}
echo $distance
result
3, 6, 2, 7, 8
i want to show like this
2, 3, 6, 7, 8
sort works on an array, and what you are doing is you are calling sort on every item in the array which wont work.
What you can do instead is do your foreach loop and then sort after:
$array = [];
foreach ($this->items as $i => $item) {
$distance = $item->result1 * $item->result2;
$array[] = $distance;
}
sort($array);
var_dump($array);
https://www.php.net/manual/en/function.sort.php
First Convert your result $this->items into (array)$this->items and then use one of the following function :
sort() - sort arrays in ascending order
rsort() - sort arrays in descending order
asort() - sort associative arrays in ascending order, according to the value
ksort() - sort associative arrays in ascending order, according to the key
arsort() - sort associative arrays in descending order, according to the value
krsort() - sort associative arrays in descending order, according to the key
and get sorted value.
There are a few things here that don't make sense to me, so I'll blindly try to refactor your scripts and put all of the processing in the model where it belongs (you shouldn't be manipulating data in the view).
Untested snippet:
$db = $this->getDbo();
$query = $db->getQuery(true)
->select('result1 * result2')
->from('#__load')
->orderBy(1);
$db->setQuery($query);
return $db->loadColumn();
Relevant pages to read:
How can a query multiply 2 cell for each row MySQL?
what is this order by 1?
https://docs.joomla.org/Selecting_data_using_JDatabase
I expect that your view will now receive the following sorted and indexed array:
$this->items = [2, 3, 6, 7, 8];
If you are a Joomla user, come join us at Joomla Stack Exchange. Have a browse of my answers to mysql tagged questions for explained examples and best practices.
If you are living in Brisvegas, come to our monthly Joomla User Group Meetup in West End (we aren't scary people). This is a place where you can leverage an IRL network of people that want to help you grow your skills and get your projects finished.

Get all elements of array in query laravel

I am trying to loop in an array but when it comes to the query it gets only the first element, so a little help would be very important.
$data = Offers::whereIn('id_business', $business_id_array)
->where([
'visible' => 'yes',
'delete' => 'no'
])
->where('end_date', '>=', date('Y-m-d h:m:i'))
->orderBy('id', 'desc')
->get();
$data=array($data);
foreach($data as $key => $item) {
$offers = DB::select('the data i need to get WHERE o.`id` = ' . $item[$key]['id']);
}
and this is my problem in here, It gets only the id of the first element
o.`id` = ' . $item[$key]['id']
because you have return the view in side the foreach loop, so it only loop through the first item and return. What you can do with this case is
$data = Offers::whereIn('id_business', $business_id_array)...->get()->toArray();
$offers = array_map(function($item){
$offer = DB::select('the data i need to get WHERE o.`id` = ?', [$item->id]);
return $offer;
},$data);
return view(....,['offers' =>$offers]);
First, you do not need to cast the $data to an array - it will get returned as a collection, which you can iterate through like an array. So you'll be able to use something like this
$offers = Offers::whereIn('id_business', $business_id_array)...->get();
foreach ($offers as $offer) {
$moreData = DB::select('the data i need to get WHERE o.`id` = ?', [$offer->id]);
}
This looks like you are using the id from one table, to get the associated data from another table.
Should there not be a relationship in place, between the two tables?
The answer from #Chris G looks correct, maybe dd($offers) to be certain what is in there.
Mick

Laravel eloquent, how to order custom sortby

I have the following code that works fine:
$products = Product::like($search)->whereIn('id', $request->input('product_ids'))->skip($offset)->take($limit)->get(array('products.*'))->sortBy(function($product) use ($sort_order) {
$number = (isset($sort_order[$product->id])) ? $sort_order[$product->id] : 0;
return $number;
});
This returns the items in ascending order, how do I specify whether I want sortby to return the products in ascending or descending order?
//$order contains either 'asc' or 'desc'
$products = Product::like($search)->whereIn('id', $request->input('product_ids'))->skip($offset)->take($limit)->get(array('products.*'))->sortBy(function($product) use ($sort_order, $direction) {
$number = (isset($sort_order[$product->id])) ? $sort_order[$product->id] : 0;
return ($direction == 'asc') ? $number : -$number;
});
I really don’t understand the query. There’s a lot going on there that really shouldn’t be. For example:
You’re not selecting data from any other table, so why are you specifying all rows from the products table in the get() method (->get(array('products.*')))?
Why are you applying the ordering function to the returned collection instead of just applying the order clause to the query?
With the above, you query could be simplified to something like:
$productIds = [1, 2, 3, 4];
$direction = 'asc'; // or desc
$products = Product::like($search)
->whereIn('id', $productIds)
->skip($offset)
->take($limit)
->orderBy('id', $direction)
->get();
Also, you don’t need to manually specify the offset and limit if you use the paginate() helper method.
Just use sortBy for ASC (how you used it now) and sortByDesc for DESC.

PHP sort array through personalized order

I need to sort an array, I've done this before but it has been easy because the array had numbers or letters to sort in ascedning/descending or alphabetical order.. In this case i have an array of which each element has 3 values, eg:
array[0]=code=1234
=description='example array'
=orderCode=P
array[1]=code=1235
=description='example array1'
=orderCode=A
.
.
.
Now i need to order theese reading the orderCode value in this order: P,I,B,C,A,S,D.
The way i thought of getting arround it was to add another value to the array and to something like:
if($array[$c]['orderCode'] == 'P')
$array[$c]['newOrderCode'] = 0;
if($array[$c]['orderCode'] == 'I')
$array[$c]['newOrderCode'] = 1;
if($array[$c]['orderCode'] == 'B')
$array[$c]['newOrderCode'] = 2;
or a switch case and then order it by the new value. This would work, but my question is, is there a function I can pass the array to and an orderring string or something?
Thank you,
James
In php 5.3 and above you can use usort with a closure.
$order = array('P','I','B','C','A','S','D');
usort($array, function ($a, $b) use ($order){
return array_search($a["orderCode"], $order) - array_search($b["orderCode"], $order);
});
prior to that you have to create a sorter function
function orderCode_sorter($a, $b){
$order = array('P','I','B','C','A','S','D');
return array_search($a["orderCode"], $order) - array_search($b["orderCode"], $order);
}
usort($array, "orderCode_sorter");
use function user defined and choise sort by key or value you need see all list function here: http://www.php.net/manual/en/array.sorting.php

Categories