Сложная сортировка Laravel Eloquent в PHP

У меня есть довольно сложная коллекция laravel eloquent, которую нужно отсортировать по идентификатору проекта, дате, имени пользователя.

Я искал в Google, но никто не спрашивал и не писал об этой сложной сортировке.

Если я использую только порядок по убыванию или возрастанию с функцией sortBy. Это работает, но если я пытаюсь использовать desc/asc, они смешиваются.

Как я могу решить эту проблему???

структура коллекции

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"
}

Это должно быть отсортировано так

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

person fiddlest    schedule 24.02.2016    source источник
comment
Что вы пытаетесь сделать здесь? Вы пытаетесь создать новую коллекцию или отсортировать существующую?   -  person An Overflowed Stack    schedule 25.02.2016
comment
По сути, я получил данные и получил красноречивую коллекцию с отношениями. Разбираю существующий.   -  person fiddlest    schedule 25.02.2016
comment
Затем, если вы отсортируете их по нескольким критериям, результат будет смешанным. Потому что вы не можете гарантировать, что тот, у кого максимальный идентификатор, также имеет максимальную дату, которая также имеет максимальное имя   -  person An Overflowed Stack    schedule 25.02.2016
comment
Так что нет решения для этого ??   -  person fiddlest    schedule 25.02.2016
comment
Глупое решение: разбить коллекцию и поместить свойства в три разных массива. Сортируйте их. Создайте новую коллекцию.   -  person An Overflowed Stack    schedule 25.02.2016
comment
Разумное решение: используйте что-то вроде C# LINQ. Я не уверен, что в laravel есть эта функция. Вся цель теперь другая. Вы создаете новую коллекцию вместо того, чтобы сортировать существующую.   -  person An Overflowed Stack    schedule 25.02.2016
comment
Я думаю, что было бы проще и проще использовать построитель запросов и разрешить сортировку mysql.   -  person user1669496    schedule 25.02.2016
comment
Проблема в том, что я не использую конструктор запросов. Я использую красноречивые отношения   -  person fiddlest    schedule 25.02.2016
comment
Вопрос: вы хотите, чтобы ваши пользователи всегда упорядочивались по именам?   -  person jardis    schedule 25.02.2016
comment
да Это всегда должно быть упорядочено по идентификатору проекта, дате и имени пользователя   -  person fiddlest    schedule 25.02.2016
comment
К какому классу относятся проекты и пользователи?   -  person jardis    schedule 25.02.2016
comment
Кроме того, не могли бы вы сообщить нам, как вы хотите, чтобы данные были структурированы. Это меняет способ написания. Трудно понять, хотите ли вы по-прежнему иметь коллекцию с загруженными отношениями, коллекцию, которая просто отсортирована по своим отношениям, или коллекцию данных, сглаженных, как вы показали для своей сортировки.   -  person jardis    schedule 25.02.2016


Ответы (1)


Вы можете делать что хотите, но вы должны использовать метод sort(), а не метод sortBy(). Метод sort() примет замыкание, которое можно использовать для определения собственного алгоритма сортировки. По сути, если вы передадите замыкание в sort(), он вызовет usort() PHP с вашим закрытие для сортировки предметов.

Это лишь приблизительное представление о том, что вы ищете. Вам, вероятно, придется настроить его, так как есть несколько неопределенностей в том, что вы опубликовали. Вы можете определить это как фактическую функцию для передачи в sort(), или вы можете просто передать ее в sort() как анонимную функцию.

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;
}

Для получения дополнительной информации о том, как работает usort(), вы можете ознакомиться с документацией.

person patricus    schedule 25.02.2016