fix: inject foto_url (full absolute URL) di API response Kontrakan & Laundry

- Tambah accessor getFotoUrlAttribute() di model Kontrakan & Laundry
  yang mengecek keberadaan file di disk (menangani casing folder berbeda)
- Inject foto_url di SAWController.sanitizeItemForMobile()
- Semua API response sekarang menyertakan foto_url siap pakai untuk mobile
This commit is contained in:
micko samawa 2026-06-28 13:26:50 +07:00
parent d26c52a5c9
commit f197bfaccb
3 changed files with 95 additions and 0 deletions

View File

@ -633,6 +633,8 @@ private function getNilaiLaundry($item, $field, $jenisLayanan = null)
/** /**
* Sanitize any image URLs in the item array/object by removing external placeholders * Sanitize any image URLs in the item array/object by removing external placeholders
* to avoid mobile clients attempting TLS connections to via.placeholder.com. * to avoid mobile clients attempting TLS connections to via.placeholder.com.
* Also injects foto_url (full absolute URL) so mobile doesn't need to guess
* the upload folder casing (uploads/kontrakan vs uploads/Kontrakan, etc.).
*/ */
private function sanitizeItemForMobile($item) private function sanitizeItemForMobile($item)
{ {
@ -652,6 +654,31 @@ private function sanitizeItemForMobile($item)
}; };
$sanitize($arr); $sanitize($arr);
// Inject foto_url: full absolute URL so mobile doesn't need to guess folder casing
if (!empty($arr['foto'])) {
$foto = $arr['foto'];
if (str_starts_with($foto, 'http')) {
// Already a full URL
$arr['foto_url'] = $foto;
} else {
$baseUrl = rtrim(url('/'), '/');
// Detect correct folder by checking file existence on disk
if (file_exists(public_path('uploads/kontrakan/' . $foto))) {
$arr['foto_url'] = $baseUrl . '/uploads/kontrakan/' . $foto;
} elseif (file_exists(public_path('uploads/Laundry/' . $foto))) {
$arr['foto_url'] = $baseUrl . '/uploads/Laundry/' . $foto;
} elseif (file_exists(public_path('uploads/Kontrakan/' . $foto))) {
$arr['foto_url'] = $baseUrl . '/uploads/Kontrakan/' . $foto;
} else {
// Fallback: build URL from kontrakan path
$arr['foto_url'] = $baseUrl . '/uploads/kontrakan/' . $foto;
}
}
} else {
$arr['foto_url'] = null;
}
return $arr; return $arr;
} }
} }

View File

@ -32,6 +32,40 @@ class Kontrakan extends Model
'availability_confirmed_at' => 'datetime', 'availability_confirmed_at' => 'datetime',
]; ];
/**
* Tambahkan foto_url ke semua JSON response secara otomatis
*/
protected $appends = ['foto_url'];
/**
* Accessor: foto_url = full absolute URL foto utama
* Mengecek keberadaan file di disk agar URL selalu benar,
* terlepas dari casing nama folder (kontrakan vs Kontrakan).
*/
public function getFotoUrlAttribute(): ?string
{
if (empty($this->foto)) {
return null;
}
$foto = $this->foto;
if (str_starts_with($foto, 'http')) {
return $foto;
}
// Cek keberadaan file di tiap kemungkinan folder
$folders = ['uploads/kontrakan', 'uploads/Kontrakan'];
foreach ($folders as $folder) {
if (file_exists(public_path($folder . '/' . $foto))) {
return url($folder . '/' . $foto);
}
}
// Fallback: konstruksi URL dengan folder lowercase (standar)
return url('uploads/kontrakan/' . $foto);
}
/** /**
* ========== RELASI ADMIN ========== * ========== RELASI ADMIN ==========
*/ */

View File

@ -25,6 +25,40 @@ class Laundry extends Model
'foto', 'foto',
]; ];
/**
* Tambahkan foto_url ke semua JSON response secara otomatis
*/
protected $appends = ['foto_url'];
/**
* Accessor: foto_url = full absolute URL foto utama laundry
* Mengecek keberadaan file di disk agar URL selalu benar,
* terlepas dari casing nama folder (Laundry vs laundry).
*/
public function getFotoUrlAttribute(): ?string
{
if (empty($this->foto)) {
return null;
}
$foto = $this->foto;
if (str_starts_with($foto, 'http')) {
return $foto;
}
// Cek keberadaan file di tiap kemungkinan folder
$folders = ['uploads/Laundry', 'uploads/laundry'];
foreach ($folders as $folder) {
if (file_exists(public_path($folder . '/' . $foto))) {
return url($folder . '/' . $foto);
}
}
// Fallback: konstruksi URL dengan folder Laundry (standar saat ini)
return url('uploads/Laundry/' . $foto);
}
/** /**
* Relasi: 1 Laundry punya banyak Layanan * Relasi: 1 Laundry punya banyak Layanan
*/ */