-
Notifications
You must be signed in to change notification settings - Fork 34
Description
- Laravel Version: 12.17.0
- Nova Version: 5.7.2
- PHP Version: 8.4.8
- Database Driver & Version: MySQL 8
- Operating System and Version: Ubuntu 24
- Browser type and version: Chrome
- Reproduction Repository: None
Description:
When ordering the table in Nova by a column that has the same value more than once, you will likely see the same record twice, or some not at all, when switching between pages.
The explanation is quite simple here, and it just comes down to how the database handles sorting in such cases. It does not guarantee that you will see the same order when limiting + offsetting (paginating) records. To mitigate that, a secondary column with unique values must be provided for sorting to ensure consistency, which Nova surprisingly does not do by default.
I found that this issue was already reported back in 2022, but closed: #4481
Detailed steps to reproduce the issue on a fresh Nova installation:
Add a Nova resource with a field that has multiple non-unique values, enough to have at least 2 pages, sort by that column, and switch pages. As a result, you will see some records appear for the second time, and some will be missing.
Fix:
Logic in applyOrderings needs to be changed to apply ordering by model key at the end by default.
I also added an option to specify default ordering for a resource using a static property called $orderBy,
following the general Nova convention. It was requested in #156.
protected static function applyOrderings($query, array $orderings): Builder
{
$orderings = array_filter($orderings);
if (empty($orderings) && property_exists(static::class, 'orderBy')) {
$orderings = array_filter(static::$orderBy);
}
if (empty($orderings)) {
return empty($query->getQuery()->orders) && ! static::usesScout()
? static::defaultOrderings($query)
: $query;
}
foreach ($orderings as $column => $direction) {
$query->orderBy($column, $direction);
}
return ! static::usesScout()
? static::defaultOrderings($query)
: $query;
}