'decimal:1', 'is_video' => 'boolean', 'latitude' => 'decimal:7', 'longitude' => 'decimal:7', ]; } public function setImageAttribute(?string $value): void { $this->attributes['image'] = $this->normalizeStoredFilePath($value); } public function setModelPathAttribute(?string $value): void { $this->attributes['model_path'] = $this->normalizeStoredFilePath($value); } public function setVideoPathAttribute(?string $value): void { $this->attributes['video_path'] = $this->normalizeStoredFilePath($value); } public function kategori(): BelongsTo { return $this->belongsTo(Kategori::class); } public function fileUrl(?string $path): ?string { if (! $path) { return null; } if (Str::startsWith($path, ['http://', 'https://'])) { return $path; } $storagePath = $this->publicStoragePath($path); if ($storagePath && Storage::disk('public')->exists($storagePath)) { return asset('storage/'.$storagePath); } $publicPath = $this->publicAssetPath($path); return $publicPath && file_exists(public_path($publicPath)) ? asset($publicPath) : null; } public function getImageUrlAttribute(): string { return $this->fileUrl($this->image) ?? asset('images/placeholders/wisata.svg'); } public function getRatingLabelAttribute(): string { return number_format((float) $this->rating, 1).' ⭐'; } public function publicStoragePath(?string $path): ?string { if (! $path || Str::startsWith($path, ['http://', 'https://'])) { return null; } $path = ltrim(str_replace('\\', '/', $path), '/'); foreach (['/storage/app/public/', '/public/storage/'] as $needle) { if (str_contains($path, $needle)) { $path = Str::after($path, $needle); break; } } foreach (['storage/app/public/', 'public/storage/', 'storage/', 'public/'] as $prefix) { if (Str::startsWith($path, $prefix)) { $path = Str::after($path, $prefix); } } return $path ?: null; } private function normalizeStoredFilePath(?string $path): ?string { if (! $path) { return null; } if (Str::startsWith($path, ['http://', 'https://'])) { return $path; } return $this->publicStoragePath($path); } private function publicAssetPath(string $path): ?string { $path = ltrim(str_replace('\\', '/', $path), '/'); if (Str::startsWith($path, 'public/')) { $path = Str::after($path, 'public/'); } return $path ?: null; } public function getTypeAttribute(): string { if ($this->model_path) { return 'ar'; } if ($this->is_video) { return 'video'; } return 'normal'; } public function getGoogleMapsUrlAttribute(): ?string { if ($this->latitude === null || $this->longitude === null) { return null; } return "https://www.google.com/maps?q={$this->latitude},{$this->longitude}"; } }