Using an index column for display purposes in your models is a common practice and can be quite effective for allowing custom ordering of items, such as products in an e-commerce application. However, if you want to make this functionality more reusable and maintainable, creating a trait with a polymorphic relationship is a good approach. Here's how you can implement it:
-
Create the
IndexableTrait:This trait will handle the logic for ordering and reordering items.
namespace App\Traits; use Illuminate\Database\Eloquent\Model; trait Indexable { public static function bootIndexable() { static::creating(function (Model $model) { if (is_null($model->index)) { $model->index = $model->getMaxIndex() + 1; } }); } public function scopeOrdered($query) { return $query->orderBy('index'); } public function getMaxIndex() { return $this->newQuery()->max('index'); } public function reorder($newIndex) { $this->index = $newIndex; $this->save(); } } -
Add the
indexColumn to Your Models:Ensure that your models have an
indexcolumn in their respective tables. You can add this column using a migration:use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class AddIndexToYourModelTable extends Migration { public function up() { Schema::table('your_model_table', function (Blueprint $table) { $table->integer('index')->nullable(); }); } public function down() { Schema::table('your_model_table', function (Blueprint $table) { $table->dropColumn('index'); }); } } -
Use the Trait in Your Models:
Apply the
Indexabletrait to any model that requires custom ordering.namespace App\Models; use Illuminate\Database\Eloquent\Model; use App\Traits\Indexable; class Product extends Model { use Indexable; // Other model properties and methods } -
Reordering Logic:
You can now use the
reordermethod to change the order of items, and theorderedscope to retrieve items in the desired order.$product = Product::find(1); $product->reorder(5); // Change the index to 5 $orderedProducts = Product::ordered()->get(); // Get products ordered by index
By using a trait, you encapsulate the logic related to indexing and make it reusable across different models. This approach also keeps your codebase clean and adheres to the DRY (Don't Repeat Yourself) principle.