baril/orderly
Add sortable, orderable behavior to Laravel Eloquent models. Store a position column (default: position), use the Orderable trait, and move records with helpers like moveToOffset() and moveToStart(). Supports Laravel 6–12 with version mapping.
Pros:
Orderable) aligns with Laravel’s conventions (e.g., $guarded, scopes).create/delete events to maintain position integrity, reducing manual intervention.orderly:fix-positions for data recovery, critical for production stability.Cons:
UPDATE queries (e.g., moveUp() affects subsequent rows). For large datasets (>10K rows), this could degrade performance without indexing or batching optimizations.saveOrder()). Concurrent writes risk race conditions.position column (or custom name), which may conflict with existing schemas or migrations.ordered() scope uses ORDER BY position, which may not leverage database-level optimizations (e.g., composite indexes) if position isn’t the primary sort criterion.position column to target tables and apply the Orderable trait.orderly:fix-positions command can retroactively populate the position column.move* methods (e.g., unsaved models, concurrent writes) can orphan positions or create gaps. Mitigate with:
saveOrder() on 10K+ rows) may time out. Test with:
position and $groupColumn (if used).position column names may clash with existing fields. Use $orderColumn to avoid collisions.position is scoped per tenant to avoid cross-tenant pollution.LISTEN/NOTIFY for real-time updates).position column must be shard-key-aware to avoid inconsistencies.version columns or SELECT ... FOR UPDATE in critical paths.order table (with model_id and sort_order) be simpler?tree packages (e.g., spatie/laravel-activitylog or nWidart/laravel-modules) suffice?fix-positions command is reactive; proactive monitoring (e.g., database triggers) may be needed.moveAfter()/moveBefore() calls on drop).position collisions).move* methods.sort_order columns).section_id) or relationships (e.g., belongsToMany) needing ordering.position column (or custom name) to tables:
Schema::table('articles', function (Blueprint $table) {
$table->unsignedInteger('position')->after('title');
});
position to the join table.Orderable trait and configure $groupColumn/$orderColumn:
class Article extends Model {
use \Baril\Orderly\Concerns\Orderable;
protected $guarded = ['position'];
protected $groupColumn = 'section_id'; // Optional
}
HasOrderableRelationships:
class Post extends Model {
use \Baril\Orderly\Concerns\HasOrderableRelationships;
public function tags() {
return $this->belongsToManyOrderable(Tag::class);
}
}
position values:
orderly:fix-positions after seeding.moveAfter()/moveBefore():
Sortable.on('articles', 'end', (evt) => {
const item = evt.item;
const target = evt.to;
axios.post(`/articles/${item.dataset.id}/move-after/${target.dataset.id}`);
});
saveOrder():
$articles = Article::orderBy('title')->get();
$articles->saveOrder(); // Saves new positions in one query
orderly:3.3 for Laravel 12).Table with sortable columns).position is included in serialized responses if needed by clients.cache()->remember), invalidate caches after position updates to avoid stale data.Orderable trait and test basic move* methods.HasOrderableRelationships to models with belongsToMany/morphToMany.setOrder().$groupColumn for sectioned ordering (e.g., articles per category).How can I help you explore Laravel packages today?