with meaning español php laravel-4 eloquent

php - meaning - ¿Cuál es la sintaxis para ordenar una colección Eloquent por múltiples columnas?



laravel find by field (4)

Como se mencionó en @derekaug, el método de sort nos permite ingresar un cierre personalizado para clasificar la colección. Pero pensé que su solución era algo engorrosa de escribir y sería bueno tener algo como esto:

$collection = collect([/* items */]) $sort = ["column1" => "asc", "column2" => "desc"]; $comparer = $makeComparer($sort); $collection->sort($comparer);

De hecho, esto se puede archivar fácilmente con el siguiente contenedor $makeComparer para generar el cierre de comparación:

$makeComparer = function($criteria) { $comparer = function ($first, $second) use ($criteria) { foreach ($criteria as $key => $orderType) { // normalize sort direction $orderType = strtolower($orderType); if ($first[$key] < $second[$key]) { return $orderType === "asc" ? -1 : 1; } else if ($first[$key] > $second[$key]) { return $orderType === "asc" ? 1 : -1; } } // all elements were equal return 0; }; return $comparer; };

Ejemplos

$collection = collect([ ["id" => 1, "name" => "Pascal", "age" => "15"], ["id" => 5, "name" => "Mark", "age" => "25"], ["id" => 3, "name" => "Hugo", "age" => "55"], ["id" => 2, "name" => "Angus", "age" => "25"] ]); $criteria = ["age" => "desc", "id" => "desc"]; $comparer = $makeComparer($criteria); $sorted = $collection->sort($comparer); $actual = $sorted->values()->toArray(); /** * [ * ["id" => 5, "name" => "Hugo", "age" => "55"], * ["id" => 3, "name" => "Mark", "age" => "25"], * ["id" => 2, "name" => "Angus", "age" => "25"], * ["id" => 1, "name" => "Pascal", "age" => "15"], * ]; */ $criteria = ["age" => "desc", "id" => "asc"]; $comparer = $makeComparer($criteria); $sorted = $collection->sort($comparer); $actual = $sorted->values()->toArray(); /** * [ * ["id" => 5, "name" => "Hugo", "age" => "55"], * ["id" => 2, "name" => "Angus", "age" => "25"], * ["id" => 3, "name" => "Mark", "age" => "25"], * ["id" => 1, "name" => "Pascal", "age" => "15"], * ]; */ $criteria = ["id" => "asc"]; $comparer = $makeComparer($criteria); $sorted = $collection->sort($comparer); $actual = $sorted->values()->toArray(); /** * [ * ["id" => 1, "name" => "Pascal", "age" => "15"], * ["id" => 2, "name" => "Angus", "age" => "25"], * ["id" => 3, "name" => "Mark", "age" => "25"], * ["id" => 5, "name" => "Hugo", "age" => "55"], * ]; */

Ahora, ya que estamos hablando de Eloquent aquí, es muy probable que también estés usando Laravel. Así que incluso podríamos vincular el $makeComparer() al IOC y resolverlo desde allí:

// app/Providers/AppServiceProvider.php // in Laravel 5.1 class AppServiceProvider extends ServiceProvider { /** * ... */ /** * Register any application services. * * @return void */ public function register() { $this->app->bind("collection.multiSort", function ($app, $criteria){ return function ($first, $second) use ($criteria) { foreach ($criteria as $key => $orderType) { // normalize sort direction $orderType = strtolower($orderType); if ($first[$key] < $second[$key]) { return $orderType === "asc" ? -1 : 1; } else if ($first[$key] > $second[$key]) { return $orderType === "asc" ? 1 : -1; } } // all elements were equal return 0; }; }); } }

Ahora puedes usarlo en todos los lugares que necesites, así:

$criteria = ["id" => "asc"]; $comparer = $this->app->make("collection.multiSort",$criteria); $sorted = $collection->sort($comparer); $actual = $sorted->values()->toArray();

Sé que al usar el generador de consultas, es posible ordenar por varias columnas usando

...orderBy(''column1'')->orderBy(''column2'')

pero ahora estoy tratando con un objeto de collection . Las colecciones tienen el método sortBy , pero no he podido encontrar la manera de hacerlo funcionar para varias columnas. Intuitivamente, inicialmente intenté usar la misma sintaxis que orderBy .

sortBy(''column1'')->sortBy(''column2)

pero esto aparentemente solo aplica los géneros secuencialmente y termina ordenado por column2, sin tener en cuenta column1. Lo intenté

sortBy(''column1'', ''column2'')

pero eso arroja el error "asort () espera que el parámetro 2 sea largo, cadena dada". Utilizando

sortBy(''column1, column2'')

no arroja un error, pero el género parece ser bastante aleatorio, así que no sé realmente qué es lo que realmente hace. Miré el código para el método sortBy , pero desafortunadamente estoy teniendo dificultades para entender cómo funciona.


Encontré una manera diferente de hacer esto usando sort() en la Colección elocuente. Es posible que funcione un poco mejor o al menos sea un poco más fácil de entender que rellenar los campos. Me interesaría ver cuál funciona mejor, ya que este tiene más comparaciones, pero no estoy haciendo el sprintf() para cada elemento.

$items->sort( function ($a, $b) { // sort by column1 first, then 2, and so on return strcmp($a->column1, $b->column1) ?: strcmp($a->column2, $b->column2) ?: strcmp($a->column3, $b->column3); } );


Una solución simple es encadenar sortBy () varias veces en orden inverso al modo en que las quiere ordenar. Lo malo es que es probable que sea más lento que ordenar de una vez en la misma devolución de llamada, por lo que debe usarlo bajo su propio riesgo en colecciones grandes.

$collection->sortBy(''column3'')->sortBy(''column2'')->sortBy(''column1'');


sortBy() realiza un cierre, lo que le permite proporcionar un único valor que se debe usar para ordenar comparaciones, pero puede hacerlo un compuesto al concatenar varias propiedades juntas

$posts = $posts->sortBy(function($post) { return sprintf(''%-12s%s'', $post->column1, $post->column2); });

Si necesita sortBy contra varias columnas, probablemente necesite espaciarlas para asegurarse de que "ABC" y "DEF" aparecen después de "AB" y "DEF", por lo tanto, el sprint derecho se rellenó para cada columna hasta la longitud de la columna ( al menos para todos menos la última columna)

Tenga en cuenta que, en general, es mucho más eficiente si puede usar un pedidoPor en su consulta para que la colección esté lista-ordenada en la recuperación de la base de datos.