composer require nevadskiy/laravel-position and publish the migration with php artisan vendor:publish --provider="Nevadskiy\Position\PositionServiceProvider".HasPosition trait to your Eloquent model (e.g., Category, MenuItem).position column (unsigned integer) to your table.$categories = Category::ordered()->get();
ordered() on a query builder to sort models by their position column.$model->position = 10; and save.position column is indexed for performance.Dynamic Positioning
position field to reorder items via AJAX (e.g., update position on sortablejs events).Category::whereIn('id', [1, 2, 3])->updatePositions([10, 20, 30]);
Query Integration
ordered() to any query:
Category::whereActive(true)->ordered()->get();
Category::ordered()->limit(5)->get(); // Top 5 by position
Position Management
insertAtPosition($position) to place a new model at a specific rank:
$newCategory = new Category(['name' => 'New']);
$newCategory->insertAtPosition(5); // Insert at position 5
$model->position = null; // Demote to end of list
$model->save();
API/Controller Patterns
public function updateOrder(Request $request) {
$request->validate(['items' => 'required|array']);
Category::updatePositions($request->items);
return response()->json(['success' => true]);
}
return Category::ordered()->get()->map(function ($item) {
return ['id' => $item->id, 'name' => $item->name, 'position' => $item->position];
});
Admin Panel Integration
// Nova Tool Example
public function fields(Request $request) {
return [
Text::make('Position', 'position'),
// ... other fields
];
}
Position Collisions
updatePositions() to auto-adjust gaps or validate uniqueness in migrations:
$table->integer('position')->unique()->index();
Performance with Large Datasets
position can be slow.position + other fields:
Schema::table('categories', function (Blueprint $table) {
$table->index(['position', 'name']);
});
limit() or pagination to reduce query load.Transaction Conflicts
DB::transaction(function () {
Category::updatePositions([10, 20, 30]);
});
Null Position Handling
position = null may appear at the start/end unpredictably.Category::ordered()->orderBy('position', 'asc')->get();
position = 0 for "unpositioned" items if needed.Query Inspection
\DB::enableQueryLog();
Category::ordered()->get();
\Log::info(\DB::getQueryLog());
Position Validation
public function saving(Category $category) {
if ($category->position && $category->position < 0) {
throw new \Exception('Position must be positive.');
}
}
Migration Rollback
position column during rollback.public function down() {
Schema::table('categories', function (Blueprint $table) {
$table->dropColumn('position');
});
}
Custom Position Logic
getPositionAttribute or setPositionAttribute methods in your model:
public function getPositionAttribute($value) {
return $value ?: 9999; // Default to high value if null
}
Scope Customization
HasPosition trait to add custom scopes:
public function scopeActiveOrdered($query) {
return $query->whereActive(true)->ordered();
}
Event Hooks
Category::updated(function ($category) {
if ($category->isDirty('position')) {
event(new PositionUpdated($category));
}
});
Database-Level Triggers
Soft Deletes
position updates respect deleted items:
Category::withTrashed()->ordered()->get();
How can I help you explore Laravel packages today?