0

I have quite complex laravel eloquent collection which need to be sorted by projectid,date, username.

I have been searching google but no one had asked or wrote about this complex sort.

If I only use desc or asc order with sortBy function. It works but if i try to use desc/asc both it mix up..

How can I solve this problem???

collection structure

collection {
    array (size=148)
      0 => 
          attribute:
                id:100,
                date:"2015-02-03"
          relations: 
               0 project(belongstomany relationship)
                      projectid: 1
               1 user(belongstomany relationship)
                      username:"test"
}

This should be sorted like this

project id(desc)   date(desc)  name(asc)
9                  2015-02-31  test1
9                  2015-02-30  test2
8                  2015-02-30  test2
7                  2015-02-29  test3
6                  2015-02-28  test4
5                  2015-02-27  test5
12
  • What are you trying to do here? Are you trying to create a new collection or sort a existing one? Commented Feb 24, 2016 at 21:39
  • Basically, I retrieved data and have eloquent collection with relationships. I am sorting existing one. Commented Feb 24, 2016 at 21:41
  • Then if you sort them on multiple criteria, the result will mix. Because you cannot guarantee the one with max id also has max date which also has max name Commented Feb 24, 2016 at 21:45
  • So there is no solution for this ?? Commented Feb 24, 2016 at 21:47
  • The dumb solution: Break the collection and put the properties into three different arrays. Sort them. Create a new collection. Commented Feb 24, 2016 at 21:51

1 Answer 1

1

You can do what you want, but you have to use the sort() method, not the sortBy() method. The sort() method will take a closure that you can use to define your custom sort algorithm. Basically, if you pass a closure to sort(), it will call PHP's usort() with your closure to sort the items.

This is just a rough idea of what you're looking for. You will probably have to tweak it since there are few uncertainties from what you've posted. You can define this as an actual function to pass into sort(), or you can just pass it into sort() as an anonymous function.

function ($a, $b) {
    /**
     * Your question states that project is a belongsToMany relationship.
     * This means that project is a Collection that may contain many project
     * objects, and you need to figure out how you want to handle that. In
     * this case, I just take the max projectid from the Collection (max,
     * since this field will be sorted desc).
     * 
     * If this is really just a belongsTo, you can simplify this down to
     * just $a->project->projectid, etc.
     */
    $aFirst = $a->project->max('projectid');
    $bFirst = $b->project->max('projectid');

    /**
     * If the projectids are equal, we have to dig down to our next comparison.
     */    
    if ($aFirst == $bFirst) {
        /**
         * Since the first sort field (projectids) is equal, we have to check
         * the second sort field.
         */

        /**
         * If the dates are equal, we have to dig down to our next comparison.
         */
        if ($a->date == $b->date) {
            /**
             * Your question states that user is a belongsToMany relationship.
             * This means that user is a Collection that may contain many user
             * objects, and you need to figure out how you want to handle that.
             * In this case, I just take the min username from the Collection
             * (min, since this field will be sorted asc).
             */
            $aThird = $a->user->min('username');
            $bThird = $b->user->min('username');

            /**
             * If the final sort criteria is equal, return 0 to tell usort
             * that these two array items are equal (for sorting purposes).
             */
            if ($aThird == $bThird) {
                return 0;
            }

            /**
             * To sort in ascending order, return -1 when the first item
             * is less than the second item.
             */
            return ($aThird < $bThird) ? -1 : 1;
        }

        /**
         * To sort in descending order, return +1 when the first item is
         * less than the second item.
         */
        return ($a->date < $b->date) ? 1 : -1;
    }

    /**
     * To sort in descending order, return +1 when the first item is
     * less than the second item.
     */
    return ($aFirst < $bFirst) ? 1 : -1;
}

For more information on how usort() works, you can check the docs.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.