Should relationships in models be ordered ? Is this a valid scenario or should the ordering be performed elsewhere:
class Category extends Model
{
use HasFactory;
protected $fillable = ['name', 'parent_id', 'slug', 'position'];
public function parent()
{
return $this->belongsTo(Category::class, 'parent_id');
}
public function children()
{
return $this->hasMany(Category::class, 'parent_id')
->orderBy('position');
}
public function posts()
{
return $this->hasMany(Post::class)
->orderBy('position');
}
}
The category table has a self-referencing parent category.
@glukinho For cases like this, I’ll create a trait that automatically applies a global scope, so that the scope can be removed if I don’t want records ordering for whatever reason (i.e. listed by last updated date).
Sorting is something I’ve previously created a trait/scope around. My trait/scope looks like this:
trait Sortable
{
public static function bootSortable(): void
{
static::addGlobalScope('sorting', new SortingScope());
static::creating(function (Model $model) {
if (empty($model->getAttribute($model->getPositionColumn()))) {
$model->setAttribute($model->getPositionColumn(), $model->getNextPosition());
}
});
}
public function initializeSortable(): void
{
$this->mergeCasts([
$this->getPositionColumn() => 'integer',
]);
}
public function getPositionColumn(): string
{
return 'position';
}
protected function getNextPosition(): int
{
return static::query()->max($this->getPositionColumn()) + 1;
}
}
class SortingScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->orderBy($model->getPositionColumn());
}
public function extend(Builder $builder)
{
$builder->macro('withoutSorting', function (Builder $builder) {
return $builder->withoutGlobalScope($this);
});
}
}