|array>|array $value The actual setting value. * @package App\Models */ class GeneralSetting extends Model { use IsCachedAsCollection; /** * The primary key for the model. * * @var string */ protected $primaryKey = 'type'; /** * The "type" of the primary key ID. * * @var string */ protected $keyType = SettingsType::class; /** * Indicates if the IDs are auto-incrementing. * * @var boolean */ public $incrementing = false; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'value' ]; /** * The attributes that should be cast. * * @var array */ protected $casts = [ 'type' => SettingsType::class, 'value' => 'json' ]; /** * Perform any actions required after the model boots. * * @return void * @throws \ErrorException Not allowed to create an instance of this. */ protected static function booted(): void { static::creating(fn () => throw new \ErrorException('Not allowed to create an instance of this')); static::updated(function (self $model) { if ($model->type === SettingsType::hotNews) { FileStorageHelper::removeOldFiles( Arr::wrap(Arr::get($model->getOriginal('value'), 'picture')), Arr::wrap($model->value['picture']) ); } self::removeCached(); }); static::deleting(fn () => throw new \ErrorException('Not allowed to create an instance of this')); } // * ROUTABLE /** * Get the value of the model's route key. * * @return mixed */ public function getRouteKey() { /** @var \App\Enums\StaticPageType */ $enum = $this->getAttribute($this->getRouteKeyName()); return $enum->value(); } /** * Get the route key for the model. * * ! Type is the routable parameter * * @return string */ public function getRouteKeyName(): string { return 'type'; } // * GETTERS /** * Mutator for 'value' attribute * * @return \Illuminate\Database\Eloquent\Casts\Attribute */ public function value(): Attribute { return Attribute::make( get: fn ($value): array => self::valueFromJson($this->type, $value), ); } // * METHODS /** * Get the json layout for a setting type. * * @param \App\Enums\Settings\SettingsType $type * * ! Note complete this with pipes when adding another SettingsType. * @return array<\App\Lib\Definitions\MenuNode>|array> * @throws \ErrorException If $type is unhandled. */ public static function getJsonLayout(SettingsType $type): array { return match ($type) { SettingsType::mainMenu => collect(MenuNodeType::all()) ->filter(fn (MenuNodeType $menuNodeType) => $menuNodeType !== MenuNodeType::link) ->map(fn (MenuNodeType $nodeType) => MenuNode::make( $nodeType->value(), true, $nodeType->label(), !empty($nodeType->routeName()) ? // phpcs:ignore Generic.Files.LineLength.TooLong (new Link(routeName: $nodeType->routeName()))->toArray() : (new Link(url: 'https://example.net'))->toArray() ))->all(), SettingsType::hotNews => [ 'text' => 'le texte', 'picture' => null, 'picture_alt' => 'le texte alt de l\'image', 'picture_title' => 'le titre de l\'image', ], SettingsType::offersCount => [ 'count' => 0, ], // @phpstan-ignore-next-line default => throw new \ErrorException("No instruction to seed setting type '{$type->label()}'") }; //end match } /** * Unserialize setting value * * @param \App\Enums\Settings\SettingsType $type * @param string $json * ! Note complete this with pipes when adding another SettingsType. * @return array<\App\Lib\Definitions\MenuNode>|array> * @throws \ErrorException If $type is unhandled. */ public static function valueFromJson(SettingsType $type, string $json): array { return match ($type) { SettingsType::mainMenu => collect(json_decode($json, true)) ->map(fn (array $jsonLayout) => MenuNode::make(...$jsonLayout))->all(), SettingsType::hotNews => json_decode($json, true), SettingsType::offersCount => json_decode($json, true), // @phpstan-ignore-next-line default => throw new \ErrorException("No instruction to unserialize setting type '{$type->label()}'") }; } }