diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index d32a17b207ef..f192f9587e27 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -439,6 +439,19 @@ public function latest($column = null) return $this; } + /** + * Order the query by a column with a given set of priority values. + * + * @param (string|\BackedEnum|\UnitEnum)[]|null $priorities + * @return $this + */ + public function orderByWithPriority(string $column, ?array $priorities = [], ?string $direction = 'asc') + { + $this->query->orderByWithPriority(...func_get_args()); + + return $this; + } + /** * Add an "order by" clause for a timestamp to the query. * diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 03195c5b9f4f..26bc023522c7 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2704,6 +2704,27 @@ public function orderBy($column, $direction = 'asc') return $this; } + /** + * Order the query by a column with a given set of priority values. + * + * @param (string|\BackedEnum|\UnitEnum)[]|null $priorities + * @return $this + */ + public function orderByWithPriority(string $column, ?array $priorities = [], ?string $direction = 'asc') + { + if (empty($priorities)) { + return $this->orderBy($column, $direction); + } + + $priorities = array_map(enum_value(...), $priorities); + + $bindings = array_map(fn () => '?', $priorities); + + $sql = "FIELD({$this->grammar->wrap($column)}, ".implode(',', $bindings).')'; + + return $this->orderByRaw($sql.' '.$direction, $priorities); + } + /** * Add a descending "order by" clause to the query. * diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 53629cdff191..dc6973f14603 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2077,6 +2077,39 @@ public function testOrderBys() $this->assertEquals([1, 1, 'news', 'opinion'], $builder->getBindings()); } + public function test_order_by_with_priority_generates_expected_sql() + { + $properties = [ + 'done', + 'pending', + ]; + + $builder = $this->getBuilder(); + $builder->select('*')->from('posts')->orderByWithPriority('status', $properties); + + $this->assertSame( + 'select * from "posts" order by FIELD("status", ?,?) asc', + $builder->toSql() + ); + + $this->assertEquals($properties, $builder->getBindings()); + + $properties = [ + StringStatus::done, + StringStatus::pending, + ]; + + $builder = $this->getBuilder(); + $builder->select('*')->from('posts')->orderByWithPriority('status', $properties); + + $this->assertSame( + 'select * from "posts" order by FIELD("status", ?,?) asc', + $builder->toSql() + ); + + $this->assertEquals(array_map(fn (StringStatus $item) => $item->value, $properties), $builder->getBindings()); + } + public function testLatest() { $builder = $this->getBuilder();