F
Filament7mo ago
JanV

How to access an uploaded file without a resource

Hi there, I'm trying to figure out how to access an uploaded file without storing it in the database using a resource. I want to access the file and process it after uploading it. I have a custom page and a form with a FileUpload field. It's pretty straightforward. The documentation and other online sources require a resource, but I don't need it. Any hints or suggestions would be helpful!
8 Replies
toeknee
toeknee7mo ago
It doesn't require a resouce at all, just build the form and the fileupload field then when you run getState() it will be processed as normal
JanV
JanVOP7mo ago
Thanks for your reply. What do you mean with "run getState()"? Do you mean call the method like this?
public function form(Form $form): Form
{
return $form->schema([
FileUpload::make('audio')
->id('audio')
->directory('audio')
->getState(),
]);
}
public function form(Form $form): Form
{
return $form->schema([
FileUpload::make('audio')
->id('audio')
->directory('audio')
->getState(),
]);
}
I am new to filament so bear with me. So the question is, to be more specific, how and where can I access the uploaded file within my custom page?
Tetracyclic
Tetracyclic7mo ago
$this->form->getState() returns the state of your form within your Livewire component. The audio key will be an instance of a Livewire TemporaryUploadedFile Specifically Livewire\Features\SupportFileUploads\TemporaryUploadedFile For example, if you need a URL to link to the uploaded file on your page, something like this should work:
$audioFile = $this->form->getState()['audio'];
$url = $audioFile->temporaryUrl();
$audioFile = $this->form->getState()['audio'];
$url = $audioFile->temporaryUrl();
The Livewire file upload docs give more information on how to interact with uploaded files directly, if you're not using them within the context of a Filament resource: https://livewire.laravel.com/docs/uploads
toeknee
toeknee7mo ago
So what you are doing above is wrong in that you are using the form correctly, but you need a save action/method. in that method it works as desired so:
public function form(Form $form): Form
{
return $form->schema([
FileUpload::make('audio')
->id('audio')
->directory('audio'),
])->model(MyModel);
}

public function save(): void {
$data = $this->form->getState();

dd($data);
}
public function form(Form $form): Form
{
return $form->schema([
FileUpload::make('audio')
->id('audio')
->directory('audio'),
])->model(MyModel);
}

public function save(): void {
$data = $this->form->getState();

dd($data);
}
Should get you what you need.
JanV
JanVOP7mo ago
Thanks guys! Still no success This is the custom page
<?php

namespace App\Filament\App\Pages;

use Filament\Forms\Components\FileUpload;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Illuminate\Support\Facades\Log;

class AudioRecord extends Page implements HasForms {

protected static ?string $navigationIcon = 'heroicon-o-document-text';

protected static string $view = 'filament.app.pages.audio-record';

public array $audio;

public function form(Form $form): Form
{
return $form->schema([
FileUpload::make('audio')
->id('audio')
->directory('audio'),
]);
}

public function save(): void
{
Log::debug('submit');

$state = $this->form->getState();

Log::debug('path', [$state]);
dd($state);
}
}
<?php

namespace App\Filament\App\Pages;

use Filament\Forms\Components\FileUpload;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Illuminate\Support\Facades\Log;

class AudioRecord extends Page implements HasForms {

protected static ?string $navigationIcon = 'heroicon-o-document-text';

protected static string $view = 'filament.app.pages.audio-record';

public array $audio;

public function form(Form $form): Form
{
return $form->schema([
FileUpload::make('audio')
->id('audio')
->directory('audio'),
]);
}

public function save(): void
{
Log::debug('submit');

$state = $this->form->getState();

Log::debug('path', [$state]);
dd($state);
}
}
This is the form component
<x-filament-panels::page>
<form wire:submit="save" class="space-y-6">
{{ $this->form }}
<x-filament::button type="submit">
Transcribe
</x-filament::button>
</form>
</x-filament-panels::page>
<x-filament-panels::page>
<form wire:submit="save" class="space-y-6">
{{ $this->form }}
<x-filament::button type="submit">
Transcribe
</x-filament::button>
</form>
</x-filament-panels::page>
As soon as I select a file in from the drop-zone/field, it is automatically uploaded to the server as I can see. As soon I hit the button, the state and file is empty. What am I doing wrong?
Tetracyclic
Tetracyclic7mo ago
Ah, probably because you're not using a statePath, but using the $audio property directly. In that instance, I believe getState() will always return null when called on the form itself. You should be able to access the state of the audio component directly with $this->form->getComponent('audio')->getState() Alternatively you could replace public array $audio with public ?array $data = []; and set ->statePath('data') on the form, which should make your current code work.
JanV
JanVOP7mo ago
The problem was the chained directory; without it, the audio property was accessible with a file name. This way, I could access the uploaded file via the temp directory and move it based on my needs so far. There should be an easier way. I do not have a perfect solution, but it works for now. Thanks, Ross, for your alternative solution! I'm going to try it out, too.
mojito
mojito6mo ago
I'm dealing with the same problem, can you explain more about the chained directory?
Want results from more Discord servers?
Add your server