->fill() does not work with SpatieMediaLibraryFileUpload

I am trying to implement a form where users can come back and edit their answers or upload new files but whatever I try to fill the SpatieMediaLibraryFileUpload with the data fails. If I provide uuid, path, url it doesn't give any error but also doesn't populate the field. If I were to give UploadedFile, Media or MediaCollection it gives an error with Filament\Forms\Components\SpatieMediaLibraryFileUpload::{closure:Filament\Forms\Components\SpatieMediaLibraryFileUpload::setUp():90}(): Argument #2 ($file) must be of type string, array given this error originates from closure used in$this->getUploadedFileUsing when the function setUp has been called. It's driving me insane. I have also tried to just use relationship but still the same problem! How can I fill the field with previous data from the database? I saw something like using unsplash in the field to set the state but still didn't worked in my case.
No description
No description
Solution:
For any one having similar problems here is the solution 1. Define your model in the mount() function 2. Because lazy loading is disabled for Media model, add ->load('media') to the model you are fetching 3. Explicitly define ->model($this->yourModel) in the SpatieMediaLibraryFileUpload 4. Fill the field using the uuid of the media you're trying to use...
Jump to solution
23 Replies
toeknee
toeknee2mo ago
You would just form fill it as normal tbh you pass the media id to the field and it loads it. For example, I use getRawState with some custom sanitisation for fields and save it then send a link, then load it
Zamion101
Zamion101OP2mo ago
by media id you mean the uuid or the record id?
toeknee
toeknee2mo ago
Just look at how the data is stored, you essentially just return that. So when you save the form, you just need to pass the model in with the form->fill() So for example we store our data into a json column which has a statepath on a group of file uploads of documents, one being a cv: "documents": { "cv": { "accdd9dd-91f0-4748-957b-a40fda39a4d8": "accdd9dd-91f0-4748-957b-a40fda39a4d8" }, }
Zamion101
Zamion101OP2mo ago
I am using SpatieMediaLibraryFileUpload::make('passport.image') In the second screenshot you can see the getRawState output.
No description
No description
Zamion101
Zamion101OP2mo ago
Am I missing something? every other field is filled with correct data only the Upload fileds missing their data
toeknee
toeknee2mo ago
No, looks correct. How are oyu filling it?
Zamion101
Zamion101OP2mo ago
I have even written debugging messages nearly everywhere in BaseFileUpload as well as SpatieMediaLibraryFileUpload and Only getting thus SpatieMediaLibraryFileUpload setup->identity_document.front and BaseFileUpload setup->identity_document.front
No description
Zamion101
Zamion101OP2mo ago
I have a class ParticipantForm extends FilamentPage with use InteractsWithForms, WithFileUploads; than filling with $this->form->fill([])
toeknee
toeknee2mo ago
Ok and this form->fill() the data contains the relationship data when inspecting? Are you sure the model is with relationships as the data won't be available without it being with, obviously if you call it directly thne it gets it, but livewire works just by having the data and setting it into the form, then anything else is dropped off later.
Zamion101
Zamion101OP2mo ago
I have media records and they are bound to model Participant which is a class Participant extends Model implements HasMedia with
public function registerMediaCollections(): void
{
$this->addMediaCollection('identity_document.front')
->useDisk('encrypted_documents')
->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp'])
->singleFile();
$this->addMediaCollection('identity_document.back')
->useDisk('encrypted_documents')
->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp'])
->singleFile();
$this->addMediaCollection('passport.image')
->useDisk('encrypted_documents')
->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp'])
->singleFile();

$this->addMediaCollection('documents')
->useDisk('encrypted_documents')
->acceptsMimeTypes([
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'image/jpeg', 'image/png', 'image/webp'
]);
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('identity_document.front')
->useDisk('encrypted_documents')
->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp'])
->singleFile();
$this->addMediaCollection('identity_document.back')
->useDisk('encrypted_documents')
->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp'])
->singleFile();
$this->addMediaCollection('passport.image')
->useDisk('encrypted_documents')
->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp'])
->singleFile();

$this->addMediaCollection('documents')
->useDisk('encrypted_documents')
->acceptsMimeTypes([
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'image/jpeg', 'image/png', 'image/webp'
]);
}
and when submitting the form I am adding the media to Participant using
$this->participant = new Participant(array_merge($data, [
'group_id' => $this->group->id,
'customer_id' => 2,
'is_sponsored' => false,
'delete_after_trip' => false,
]));
$this->participant->save();
try {
$this->participant
->addMedia($identityDocumentFront)
->usingName('identity_document.front')
->usingFileName('identity_document_front.' . $identityDocumentFront->guessClientExtension())
->toMediaCollection('identity_document.front');
$this->participant
->addMedia($identityDocumentBack)
->usingName('identity_document.back')
->usingFileName('identity_document_back.' . $identityDocumentBack->guessClientExtension())
->toMediaCollection('identity_document.back');
$this->participant
->addMedia($passportImage)
->usingName('passport')
->usingFileName('passport.' . $passportImage->guessClientExtension())
->toMediaCollection('passport.image');
} catch (FileDoesNotExist|FileIsTooBig $e) {
ray($e);
}
$this->participant = new Participant(array_merge($data, [
'group_id' => $this->group->id,
'customer_id' => 2,
'is_sponsored' => false,
'delete_after_trip' => false,
]));
$this->participant->save();
try {
$this->participant
->addMedia($identityDocumentFront)
->usingName('identity_document.front')
->usingFileName('identity_document_front.' . $identityDocumentFront->guessClientExtension())
->toMediaCollection('identity_document.front');
$this->participant
->addMedia($identityDocumentBack)
->usingName('identity_document.back')
->usingFileName('identity_document_back.' . $identityDocumentBack->guessClientExtension())
->toMediaCollection('identity_document.back');
$this->participant
->addMedia($passportImage)
->usingName('passport')
->usingFileName('passport.' . $passportImage->guessClientExtension())
->toMediaCollection('passport.image');
} catch (FileDoesNotExist|FileIsTooBig $e) {
ray($e);
}
I am sure that I can get the media and view it in my controller. I am using custom Storage to encrypt the data in the filesystem as well as custom Path Generator but both of them work without a problem because I can use a route to see the decrypted file as image
No description
Zamion101
Zamion101OP2mo ago
Like I stated, I have a custom directory structure <group_id>/<participant_id>/<media_name>/<encrypted_media_file>
No description
Zamion101
Zamion101OP2mo ago
Additionally here is how I am defining the field
No description
toeknee
toeknee2mo ago
I think you've over complicated it tbh they are also stored as bin
Zamion101
Zamion101OP2mo ago
Well tell this to the goverment if you can. I am storing sensitive data so I am by law required to encrypt it Also for auditing I am require to store in a managable structure for easy auditing
toeknee
toeknee2mo ago
Ahh ok fair enough so you need to handle encryption / decryption. So makes sense
Zamion101
Zamion101OP2mo ago
Exactly. I am trying to not be fined for millions if even a sniff of possible leak is detected for not securing the informations I know it makes every step more complicated but law is law and goverments are pushing for fines in every way. Also being cautious for this kind of things are always good for the company, customer as well as marketing.
toeknee
toeknee2mo ago
Technically they don't need encrypting but need storing securely so say S3 private isoalted storage is secure by nature. But totally get it. I think that's where it will be struggling to validate the document from the .bin
Zamion101
Zamion101OP2mo ago
I agree that I can store in a S3 private storage but this also adds latency and network requests as well. Better way is to make sure information never leaves the virtual machine with a encrypted storage partition. --- I can store them with a proper extension but still required to decrypt it. I am not sure where the actual problem originates. I couldn't find proper place to start debugging. Like I have shown above in the screenshot I have added to nearly all the callbacks a debugging message but never called when filling the data. I may change it to S3 in the future if the requirements allows it but currently project requires the data to be stored locally in a encrypted partition
toeknee
toeknee2mo ago
Yeah get that, I will say the issue is the encryption back tbh so when spatie reads it it's not a valid file and disregards it...
Zamion101
Zamion101OP2mo ago
Do you have a function where I can check this theory with adding debug statements to see it. Or maybe some kind of callback where I can manipulate the state with the decrypted data?
toeknee
toeknee2mo ago
Not to my knowledge, I think you'll need to dig down into the field and package structure unforauntely, unless someone knows differently.
Zamion101
Zamion101OP2mo ago
Thank you for your help. If you know anyone with a more knowledge about the package may you mention them here for a quick look @toeknee after adding 10 more debug statements and tracing the data flow. I have found out that the $model is not defined because it's a custom FilamentPage and it's not associated with any type of Model so I required to explicitly define the mode using model($this->participant) to find the model for looking up its $model->media variable. It took long time to locate but now it works like a charm
Solution
Zamion101
Zamion1012mo ago
For any one having similar problems here is the solution 1. Define your model in the mount() function 2. Because lazy loading is disabled for Media model, add ->load('media') to the model you are fetching 3. Explicitly define ->model($this->yourModel) in the SpatieMediaLibraryFileUpload 4. Fill the field using the uuid of the media you're trying to use Here is the example
public function mount(Request $request, int $id): void
{
$this->participant = Participant::findOrFail($id)->load('media');

$this->form->fill([
...
'image' => $this->participant->getFirstMedia('some.collection')?->uuid
...
]);
}

...
// In your form use
SpatieMediaLibraryFileUpload::make('image')->model($this->participant);
public function mount(Request $request, int $id): void
{
$this->participant = Participant::findOrFail($id)->load('media');

$this->form->fill([
...
'image' => $this->participant->getFirstMedia('some.collection')?->uuid
...
]);
}

...
// In your form use
SpatieMediaLibraryFileUpload::make('image')->model($this->participant);
And you should be good to go. I hope it will be helpful

Did you find this page helpful?