key}"); }); static::deleted(function ($setting) { \Illuminate\Support\Facades\Cache::forget("app_setting_{$setting->key}"); }); } protected $fillable = [ 'key', 'value', 'value_text', 'value_boolean', 'value_file', 'value_date', 'value_datetime', 'value_array', 'value_color_picker', 'value_code_editor', 'value_rich_editor', 'value_markdown_editor', 'value_tags_input', 'value_checkbox_list', 'value_radio', 'value_toggle_buttons', 'value_slider', 'value_key_value', 'type', 'group', 'label', 'description', 'is_public', 'is_active', ]; protected $casts = [ 'is_public' => 'boolean', 'is_active' => 'boolean', ]; protected $dates = [ 'created_at', 'updated_at', 'deleted_at', ]; /** * Set value from different field names */ public function setValueTextAttribute($value) { $this->attributes['value'] = $value; } /** * Set value from different field names */ public function setValueBooleanAttribute($value) { $this->attributes['value'] = $value ? '1' : '0'; } public function setValueFileAttribute($value) { // Filament bazen dosya yolunu array olarak döndürebilir, bu durumda ilk elemanı alıyoruz if (is_array($value)) { $filePath = array_values($value)[0] ?? null; } else { $filePath = $value; } if ($filePath && $this->key === 'hero_bg') { $filePath = $this->processHeroBackground($filePath); } $this->attributes['value'] = $filePath; } /** * Process the hero background image: convert to webp, resize if necessary, and compress. */ protected function processHeroBackground($filePath) { try { $disk = \Illuminate\Support\Facades\Storage::disk('public'); if (!$disk->exists($filePath)) { return $filePath; } $absolutePath = $disk->path($filePath); // Get image info $imageInfo = @getimagesize($absolutePath); if (!$imageInfo) { return $filePath; } $mimeType = $imageInfo['mime']; // Create GD image resource based on mime type switch ($mimeType) { case 'image/jpeg': case 'image/jpg': $image = @imagecreatefromjpeg($absolutePath); break; case 'image/png': $image = @imagecreatefrompng($absolutePath); break; case 'image/webp': $image = @imagecreatefromwebp($absolutePath); break; case 'image/gif': $image = @imagecreatefromgif($absolutePath); break; default: return $filePath; } if (!$image) { return $filePath; } // Preserve transparency or handle it for webp if needed imagealphablending($image, true); imagesavealpha($image, true); $originalWidth = imagesx($image); $originalHeight = imagesy($image); // Target dimensions: Hero bg size, max width 1920px $maxWidth = 1920; if ($originalWidth > $maxWidth) { $newWidth = $maxWidth; $newHeight = (int) (($originalHeight / $originalWidth) * $maxWidth); $resizedImage = imagecreatetruecolor($newWidth, $newHeight); // Preserve transparency imagealphablending($resizedImage, false); imagesavealpha($resizedImage, true); // Resize imagecopyresampled($resizedImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $originalWidth, $originalHeight); imagedestroy($image); $image = $resizedImage; } // Generate new webp path $pathInfo = pathinfo($filePath); $newWebpPath = $pathInfo['dirname'] . '/' . $pathInfo['filename'] . '.webp'; $absoluteWebpPath = $disk->path($newWebpPath); // Save as webp with 80% quality (excellent quality-to-size ratio) if (imagewebp($image, $absoluteWebpPath, 80)) { imagedestroy($image); // If the file extension changed, delete the original file if ($newWebpPath !== $filePath) { $disk->delete($filePath); } return $newWebpPath; } imagedestroy($image); } catch (\Exception $e) { // Log error or fallback to original \Illuminate\Support\Facades\Log::error('Hero background image processing failed: ' . $e->getMessage()); } return $filePath; } /** * Set value from different field names */ public function setValueDateAttribute($value) { $this->attributes['value'] = $value; } /** * Set value from different field names */ public function setValueDatetimeAttribute($value) { $this->attributes['value'] = $value; } /** * Set value from different field names */ public function setValueArrayAttribute($value) { $this->attributes['value'] = is_array($value) ? json_encode($value) : $value; } /** * Set value from color picker */ public function setValueColorPickerAttribute($value) { $this->attributes['value'] = $value; } /** * Set value from code editor */ public function setValueCodeEditorAttribute($value) { $this->attributes['value'] = $value; } /** * Set value from rich editor */ public function setValueRichEditorAttribute($value) { $this->attributes['value'] = $value; } /** * Set value from markdown editor */ public function setValueMarkdownEditorAttribute($value) { $this->attributes['value'] = $value; } /** * Set value from tags input */ public function setValueTagsInputAttribute($value) { $this->attributes['value'] = is_array($value) ? json_encode($value) : $value; } /** * Set value from checkbox list */ public function setValueCheckboxListAttribute($value) { $this->attributes['value'] = is_array($value) ? json_encode($value) : $value; } /** * Set value from radio */ public function setValueRadioAttribute($value) { $this->attributes['value'] = $value; } /** * Set value from toggle buttons */ public function setValueToggleButtonsAttribute($value) { $this->attributes['value'] = $value; } /** * Set value from slider */ public function setValueSliderAttribute($value) { $this->attributes['value'] = (string) $value; } /** * Set value from key value */ public function setValueKeyValueAttribute($value) { $this->attributes['value'] = is_array($value) ? json_encode($value) : $value; } /** * Get value for text field */ public function getValueTextAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for boolean field */ public function getValueBooleanAttribute() { return isset($this->attributes['value']) ? filter_var($this->attributes['value'], FILTER_VALIDATE_BOOLEAN) : false; } /** * Get value for file field */ public function getValueFileAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for date field */ public function getValueDateAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for datetime field */ public function getValueDatetimeAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for array field */ public function getValueArrayAttribute() { return isset($this->attributes['value']) ? json_decode($this->attributes['value'], true) : []; } /** * Get value for color picker field */ public function getValueColorPickerAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for code editor field */ public function getValueCodeEditorAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for rich editor field */ public function getValueRichEditorAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for markdown editor field */ public function getValueMarkdownEditorAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for tags input field */ public function getValueTagsInputAttribute() { return isset($this->attributes['value']) ? json_decode($this->attributes['value'], true) : []; } /** * Get value for checkbox list field */ public function getValueCheckboxListAttribute() { return isset($this->attributes['value']) ? json_decode($this->attributes['value'], true) : []; } /** * Get value for radio field */ public function getValueRadioAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for toggle buttons field */ public function getValueToggleButtonsAttribute() { return $this->attributes['value'] ?? null; } /** * Get value for slider field */ public function getValueSliderAttribute() { return isset($this->attributes['value']) ? (int) $this->attributes['value'] : 0; } /** * Get value for key value field */ public function getValueKeyValueAttribute() { return isset($this->attributes['value']) ? json_decode($this->attributes['value'], true) : []; } /** * Find an active setting record by key. */ public static function findActiveByKey(string $key): ?self { return static::query() ->where('key', $key) ->where('is_active', true) ->first(); } /** * Get setting by key */ public static function get(string $key, $default = null) { $setting = static::findActiveByKey($key); if (!$setting) { return $default; } return static::castValue($setting->value, $setting->type); } /** * Set setting value */ public static function set(string $key, $value, string $type = 'string'): void { static::updateOrCreate( ['key' => $key], [ 'value' => $value, 'type' => $type, 'is_active' => true, ] ); } /** * Cast value based on type */ protected static function castValue($value, string $type) { return match($type) { 'boolean' => filter_var($value, FILTER_VALIDATE_BOOLEAN), 'integer' => (int) $value, 'float' => (float) $value, 'array', 'json', 'tags_input', 'checkbox_list', 'key_value' => json_decode($value, true), 'file' => $value, // File path as string 'date' => $value, // Date as string (Y-m-d format) 'datetime' => $value, // DateTime as string (Y-m-d H:i:s format) 'color_picker' => $value, // Color as hex string 'code_editor' => $value, // Code as string 'rich_editor' => $value, // HTML as string 'markdown_editor' => $value, // Markdown as string 'radio' => $value, // Radio selection as string 'toggle_buttons' => $value, // Toggle selection as string 'slider' => (int) $value, // Slider value as integer default => $value, }; } /** * Get all settings by group */ public static function getGroup(string $group): array { return static::query() ->where('group', $group) ->where('is_active', true) ->pluck('value', 'key') ->map(function ($value, $key) { $setting = static::findActiveByKey($key); return $setting ? static::castValue($value, $setting->type) : $value; }) ->toArray(); } }