Skip to main content

Implementing Sortable Models

Introduction

This guide explains how to implement sortable models in your Laravel application, allowing you to easily manage the order of records in your database. The sortable functionality is built on a robust infrastructure that automatically handles record positioning.

Key Benefit

Implementing the sortable interface allows your models to be automatically ordered, making it easy to create drag-and-drop interfaces and maintain consistent sorting across your application.

Implementation Steps

Step 1: Implement Interface and Trait

First, implement the SortableEntity interface and add the HasSorting trait to your model:

app/Models/YourModel.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Services\SortOrder\Contracts\SortableEntity;
use App\Services\SortOrder\Traits\HasSorting;

class YourModel extends Model implements SortableEntity
{
use HasSorting;

// Your model properties and methods...
}

Step 2: Configure Sort Column (Optional)

If your sort column name is different from the default order, override the sortingColumnName method:

// No need to override if using 'order' as your sort column
// The default implementation is:

public function sortingColumnName(): string
{
return 'order';
}

With the default configuration, the system will use the order column for sorting.

Database Schema

Make sure your table has the appropriate column (either order or your custom column name) defined as an integer in your migration:

$table->integer('order')->default(0);

Step 3: Define Sorting Scope (Optional)

If you need to limit sorting to specific groups of records (e.g., only sort items within the same category), override the baseSortQuery method:

// No need to override if sorting all records together
// The default implementation is:

public function baseSortQuery(): Builder
{
return $this->newQuery();
}

This will sort all records of the model together.

Available Features

After implementing the sortable interface and trait, your model will have the following capabilities:

1. Automatic Sorting of New Records

New records are automatically assigned the next available position in their sorting scope.

Creating a new record
// The new record will be placed at the end of the list
$item = YourModel::create([
'name' => 'New Item',
'category_id' => 1
]);

// No need to manually set the order - it's handled automatically

2. Item Reordering

You can easily change the position of items:

Reordering items
// Move an item up one position
$item->moveUp();

// Move an item down one position
$item->moveDown();

// Move an item to a specific position
$item->moveTo(3);

// Move an item to the first position
$item->moveToStart();

// Move an item to the last position
$item->moveToEnd();

3. Automatic Reordering After Deletion

When a record is deleted, the system automatically reorders the remaining items to maintain consecutive positions.

Deleting a record
// When this item is deleted, other items will be reordered automatically
$item->delete();

4. Order-Based Queries

Query your models in their sorted order:

Querying in sorted order
// Get all items in their sorted order
$items = YourModel::ordered()->get();

// Combine with other query conditions
$items = YourModel::where('is_active', true)
->ordered()
->get();

Infrastructure

The sorting system uses an observer pattern that is automatically applied to models implementing the SortableEntity interface. This observer handles:

  • Setting the initial order value for new records
  • Reordering records when an item's position changes
  • Cleaning up the order sequence when records are deleted

You don't need to configure the observer manually - it's automatically registered through Laravel's service provider system.

Implementation Example

app/Models/MenuItem.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Services\SortOrder\Contracts\SortableEntity;
use App\Services\SortOrder\Traits\HasSorting;

class MenuItem extends Model implements SortableEntity
{
use HasSorting;

protected $fillable = [
'name',
'url',
'menu_id',
'is_active'
];

// Override to sort within the same menu
public function baseSortQuery(): Builder
{
return $this->newQuery()
->where('menu_id', $this->menu_id);
}

// Relationship to Menu
public function menu()
{
return $this->belongsTo(Menu::class);
}
}

Conclusion

Implementing sortable models using the SortableEntity interface and HasSorting trait provides a robust foundation for managing ordered records in your Laravel application. This approach simplifies the creation of sortable lists, drag-and-drop interfaces, and any feature that requires maintaining a specific order of records.

By leveraging the automatic sorting capabilities, you can focus on building your application's unique features rather than worrying about the complexities of maintaining record order.