Created
March 21, 2025 14:51
-
-
Save leek/6b6bdb16c76469ad2268b02158d18361 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Concerns; | |
use Illuminate\Contracts\Database\Eloquent\Builder; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Database\Eloquent\SoftDeletes; | |
trait HasPrimary | |
{ | |
/** | |
* Automatically apply default values and casts. | |
*/ | |
public function initializeHasPrimary(): void | |
{ | |
$this->attributes['is_primary'] ??= false; | |
$this->casts['is_primary'] = 'boolean'; | |
} | |
/** | |
* The "booted" method of the model. | |
*/ | |
protected static function bootHasPrimary(): void | |
{ | |
static::saved(function (Model $model) { | |
if ($model->is_primary) { | |
// Ensure only one primary exists | |
static::getHasPrimaryQueryBuilder($model) | |
->whereKeyNot($model->getKey()) | |
->update([ | |
static::getHasPrimaryField() => false, | |
]) | |
; | |
} else { | |
// If no primary exists, set this as primary | |
$hasPrimary = static::getHasPrimaryQueryBuilder($model) | |
->where(static::getHasPrimaryField(), true) | |
->exists() | |
; | |
if (! $hasPrimary) { | |
$model->forceFill([static::getHasPrimaryField() => true])->saveQuietly(); | |
} | |
} | |
}); | |
static::deleted(function (Model $model) { | |
if ($model->is_primary) { | |
static::getHasPrimaryQueryBuilder($model) | |
->whereKeyNot($model->getKey()) | |
->first()?->update([ | |
static::getHasPrimaryField() => true, | |
]) | |
; | |
} | |
}); | |
} | |
/** | |
* Scope a query to only include default records. | |
*/ | |
public function scopePrimary(Builder $query): void | |
{ | |
$query->where(static::getHasPrimaryField(), true); | |
} | |
public static function getHasPrimaryField(): string | |
{ | |
return 'is_primary'; | |
} | |
/** | |
* Check if the model is primary. | |
*/ | |
public function isPrimary(): bool | |
{ | |
return (bool) $this->{static::getHasPrimaryField()}; | |
} | |
/** | |
* Base query builder that ensures soft deletes are handled. | |
*/ | |
public static function getHasPrimaryQueryBuilder(Model $model): Builder | |
{ | |
$query = $model->newQuery(); | |
// Apply model-specific constraints | |
static::applyHasPrimaryQueryFilters($query, $model); | |
// Ensure soft-deleted records are ignored | |
if (in_array(SoftDeletes::class, class_uses_recursive($model))) { | |
$query->withoutTrashed(); | |
} | |
return $query; | |
} | |
/** | |
* Allow models to define their own constraints on the query. | |
*/ | |
protected static function applyHasPrimaryQueryFilters(Builder $query, Model $model): void | |
{ | |
// Models can override this method to apply custom filtering logic. | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment