$attributes */ public static function createProp(array $attributes): Prop { return Prop::query()->create([ ...$attributes, 'propable_type' => static::class, ]); } /** * @return Builder */ public function props(): Builder { return Prop::query()->forModel(static::class); } /** * @return HasMany */ public function propValues(): HasMany { return $this->hasMany(ModelPropValue::class, 'valuable_id') ->whereHas('prop', fn (Builder $query) => $query->forModel(static::class)); } public function getPropValue(Prop|string $prop): ?ModelPropValue { $resolvedProp = $this->resolveProp($prop); return $this->propValues() ->where('prop_id', $resolvedProp->getKey()) ->first(); } public function setPropValue(Prop|string $prop, mixed $value): ModelPropValue { $this->ensurePropValuesCanBeManaged(); $resolvedProp = $this->resolveProp($prop); return $this->propValues()->updateOrCreate( ['prop_id' => $resolvedProp->getKey()], ['value' => $value], ); } /** * @param array $props */ public function syncPropValues(array $props): void { foreach ($props as $codigo => $value) { $this->setPropValue($codigo, $value); } } public function deletePropValue(Prop|string $prop): bool { $resolvedProp = $this->resolveProp($prop); return $this->propValues() ->where('prop_id', $resolvedProp->getKey()) ->delete() > 0; } protected function ensurePropValuesCanBeManaged(): void { if (! $this->exists) { throw new LogicException('Cannot manage prop values for an unsaved model.'); } } protected function resolveProp(Prop|string $prop): Prop { if ($prop instanceof Prop) { if ($prop->propable_type !== static::class) { throw new LogicException('The given prop does not belong to this model type.'); } return $prop; } return Prop::query() ->forModel(static::class) ->where('codigo', $prop) ->firstOrFail(); } }