Fix EV company logo upload to use public disk

Logos were being written to the default filesystem disk, which
resolves to storage/app/private and isn't web-servable, so the
frontend couldn't load the image. Store logos on the public disk
(storage/app/public, symlinked to public/storage) instead, and
resolve logoUrl() against that disk explicitly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015HaT8a5ZWh45JkjTLPWeaP
This commit is contained in:
Nyan Lin Paing
2026-09-03 00:30:50 +07:00
parent 31ed52500a
commit d1ce73e7ff
3 changed files with 9 additions and 6 deletions
@@ -32,7 +32,9 @@ class EvCompanyForm
->required() ->required()
->maxLength(255), ->maxLength(255),
FileUpload::make('logo') FileUpload::make('logo')
->image(), ->image()
->disk('public')
->directory('logos'),
Toggle::make('is_active') Toggle::make('is_active')
->required() ->required()
->default(true), ->default(true),
+5 -4
View File
@@ -78,9 +78,10 @@ class EvCompany extends Model
/** /**
* `logo` is stored as the disk-relative path Filament's FileUpload * `logo` is stored as the disk-relative path Filament's FileUpload
* writes (e.g. "logos/xxx.png"), not a URL API consumers need a full * writes (e.g. "logos/xxx.png"), not a URL API consumers need a full
* absolute URL to render it directly. Guards against the disk itself * absolute URL to render it directly. Logos are always written to the
* already returning an absolute URL (e.g. an s3 disk), so this stays * "public" disk (storage/app/public, symlinked to public/storage) so
* correct if the storage disk ever changes from local. * the frontend can actually reach the image, regardless of what the
* app's default filesystem disk is configured to.
*/ */
public function logoUrl(): Attribute public function logoUrl(): Attribute
{ {
@@ -90,7 +91,7 @@ class EvCompany extends Model
return null; return null;
} }
$url = Storage::disk(config('filesystems.default'))->url($this->logo); $url = Storage::disk('public')->url($this->logo);
return str($url)->startsWith(['http://', 'https://']) ? $url : url($url); return str($url)->startsWith(['http://', 'https://']) ? $url : url($url);
}, },
@@ -26,7 +26,7 @@ test('returns the company logo as a full absolute url', function () {
$this->withHeader('Authorization', "Bearer {$this->token}") $this->withHeader('Authorization', "Bearer {$this->token}")
->getJson('/api/v1/companies') ->getJson('/api/v1/companies')
->assertSuccessful() ->assertSuccessful()
->assertJsonFragment(['logo' => url(Storage::disk(config('filesystems.default'))->url($company->logo))]); ->assertJsonFragment(['logo' => url(Storage::disk('public')->url($company->logo))]);
}); });
test('returns a null logo when the company has none', function () { test('returns a null logo when the company has none', function () {