I'm a little stuck on something that usually is quite straight forward. I need to sort records from a hasMany relationship into a custom order based on a certain value and an 'sort order' array.
My code below doesn't work because I'm passing uSort() a eloquent collection and I'm not sure how to get around it.
$go = $this->hasMany('Product')->orderBy('colour','DESC');
$order = array('RED', 'GREEN', 'BLUE', 'YELLOW');
usort($go, function ($a, $b) use ($order) {
$pos_a = array_search($a->colour, $order);
$pos_b = array_search($b->colour, $order);
return $pos_a - $pos_b;
});
return $go;
Maybe I'm missing some amazing laravel magic helper, but I'm stuck. Any thoughts or advice would be much appreciated!
Cheers
The usort equivalent for Collection is the sort() method. It takes a callback as a parameter and returns the sorted collection.
So in your case, the solution is:
$go = $go->sort(function ($a, $b) use ($order) {
$pos_a = array_search($a->colour, $order);
$pos_b = array_search($b->colour, $order);
return $pos_a - $pos_b;
});
Your sorting will be applied only after you get the result while here $go = $this->hasMany('Product')->orderBy('colour','DESC'); you are just getting an instance of a class which will return can return your result if you apply a get method on it.
For your purpose you have to use sortBy method of laravel collections after you get the result of your data you can find more (laravel Collection sortBy() method) & here is a similar question answer for you https://stackoverflow.com/a/28202985
Related
Sorting a unique collection by value. I've tried sortBy but instead of the key need to sort by the value
return ($c->flatten()->unique());
Output: Need to go in chronological order
{"0":"9am","1":"10am","2":"11am","3":"1pm","4":"2pm","5":"5pm","10":"3pm","14":"12pm"}
Assuming that $c is the collection you meant, this should work:
$sorted = $c->sortBy(function($value, $key) {
return strtotime($value);
});
Sources:
Laravel 5 Collections Sorting
How to sort time by meridiem (AM/PM)
I have a question about the order in the pagination in Symfony 2.7.
Before we used pagination we used the PHP function usort to sort some things. But my question now is how could we implement the usort in the doctrine query with the same order like the usort. Which needs to be working with the Paginator. Since when we use now the query (here under) we don't get the proper results.
usort function:
usort($result, function ($a, $b) {
$aBegin = $a->getStartDate() ?: $a->getCreatedDate();
$bBegin = $b->getStartDate() ?: $b->getCreatedDate();
if ($aBegin < $bBegin) {
return -1;
}
if ($aBegin == $bBegin) {
return 0;
}
if ($aBegin > $bBegin) {
return 1;
}
return 0;
});
How could we implemented the usort in the following query:
$build = $this->createQueryBuilder('building');
$build
->addSelect('users', 'furniture')
->join('building.users', 'users')
->leftJoin('building.furniture', 'furniture')
->where('building.id = :id')
->setParameter('id', $id)
->orderBy('building.getStartDate', 'ASC')
->addOrderBy('building.getCreatedDate', 'DESC');
$paginator = new Paginator($build->getQuery(), $fetchJoinCollection = true);
$result = $paginator->getQuery()
->setFirstResult($offset)
->setMaxResults($limit)
->getResult();
Thanks!
Doctrine orm: 2.2.3,
Symfony version: 2.7
To add such a condition, you can use a CASE expression in your select clause. You can write something like CASE WHEN b.startDate IS NULL THEN b.createdDate ELSE b.startDate END to have the behaviour described in your usort function.
That being said, you can't simply add this to your order by clause. You will need to select this value, give it an alias and then add an order by based on the newly selected value. Since you probably don't want to get a mixed result (where your entities would be mixed with scalar values), you can use the HIDDEN keyword to remove the computed field from the result set.
All put together, it could look like this:
// $qb your query builder with all your other parameters
$qb->addSelect('CASE
WHEN building.startDate IS NULL
THEN building.createdDate
ELSE building.startDate
END
AS HIDDEN beginDate');
$qb->orderBy('beginDate', 'DESC');
Note that while this works, you might encounter performance issues if you have a lot of entries in your table as the whole table is very likely to be scanned entirely for this query to be executed.
It's fun with sorting today! Sigh. I have a big collection of eloquent models that need to be grouped together in the array by one parameter, and ordered in those 'clumps' based on another parameter. This might be hard to explain :(
$master is a collection of Eloquent results, I'm not sure how to write them out here, looping over this I can access all the models functions / relationships
$master = [];
These have 2 properties that need to be the basis for a sort, example of the properties below
//Object 1
$master->carry = 0;
$master->section = 'red';
//Object 2
$master->carry = 1;
$master->section = 'blue';
//Object 3
$master->carry = 0;
$master->section = 'blue';
I want to sort a massive collection of these so that each $master->section is in one 'clump' in the array and inside that 'clump' the $master->carry=0 products are listed last.
From the example above I'd expect Object1, Object3, Object2
I've tried a few different $master->sort() and $master->sortBy() things, but each new sort throws off the old sort :(
I've got the code below currently, which groups up all the colors, but it doesn't order them based on $master->carry yet
$order = array('red', 'blue', 'green');
$master = $master->sort(function ($a, $b) use ($order) {
$pos_a = array_search($a->sectionheader, $order);
$pos_b = array_search($b->sectionheader, $order);
return $pos_a - $pos_b;
});
As I understood, you want to sort your collection the following way:
sort by section in the order stored in $order array
within section move the elements with carry = 0 to the end
You need to pass a function that would implement such logic to $master collection. This function should take 2 arguments (2 elements of collection), compare them and return:
0 if elements are equal
1 if the first element is greater than the second element
-1 if the first element is smaller than the second element
In your case the following callback should work:
$master = $master->sort(function ($a, $b) use ($order) {
// get order of first element's section
$pos_a = array_search($a->section, $order);
// get order of second element's section
$pos_b = array_search($b->section, $order)
// if sections are different the value of carry doesn't matter
// as element's sections are enough to determine which of them is larger
if ($pos_a != $pos_b) {
return $pos_a - $pos_b;
}
// carry values are equal, so consider elements equal
if ($a->carry == $b->carry) {
return 0;
}
if (!$a->carry) {
// if $a->carry is equal to 0 it should be put at the end, so after $b
return 1;
}
if (!$b->carry) {
// if $b->carry is equal to 0 it should be put at the end, so after $a
return -1;
}
// otherwise elements can be considered equal
return 0;
});
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
In the function below, the $myrecentposts variable holds a collection of the 5 latest posts. How can I take these 5 posts and reorder them before they are written to the for-loop so that they are ordered by their post-title index in the array?
function getLatestPostsAndSort($post)
{
$myrecentposts = get_posts(
array('post__not_in' => get_option('sticky_posts'),
'numberposts' => 5
)
//NEED TO RESORT THE ARRAY HERE BY [POST-TITLE]
foreach($myrecentposts as $idxrecent=>$post)
{
?><li><?php the_title(); ?></li><?php
}
}
PS: the obvious suggestion might be to pull them from the database in the desired order. However, the get_posts() method offers no such option. The default order is by post date (latest first). If I change the order to "title", it does not take post date into consideration and rather just pulls the entire post collection and orders them by title.
Generally speaking, you can sort an array like:
usort($myrecentposts, function($a, $b) {
return strcmp($a['title'], $b['title']);
});
You need to adjust title to be whatever the actual name of the key is.
If this is wordpress, then based on a quick Google search, it looks like it might be:
usort($myrecentposts, function($a, $b) {
return strcmp($a->post_title, $b->post_title);
});
If you don't have PHP 5.3, then you'll need to move that anonymous function into a real one like:
function sort_post_by_title($a, $b) {
return strcmp($a->post_title, $b->post_title);
}
usort($myrecentposts, 'sort_post_by_title');
http://php.net/manual/en/function.usort.php
You need to use usort();
You can use php's usort function: http://php.net/manual/en/function.usort.php