F
Filament16mo ago
anjama

Laravel Excel not running in action

I have a csv importer built using Laravel Excel that works when tested in a seeder and in Tinker, but when using it with a file upload form inside of a modal, it seems like it's being skipped entirely inside of the action (doesn't even throw exceptions when there is an issue). Other code before and after the import inside of the action runs fine. Can anyone spot something I'm doing wrong?
Action::make('import')
->form([
FileUpload::make('data_file')
->acceptedFileTypes(['text/csv'])
->maxFiles(1)
->storeFileNamesIn('file_name')
])
->action(function (array $data): void {
//dd($data);
//try {
Excel::import(new SitesImport, 'test_data/test_sites.csv'); //Manual file name for debugging
//} catch (ValidationException $e) {
// dd($e->failures());
//}

Notification::make()
->title('Imported: ' . $data['file_name'])
->success()
->send();
})
Action::make('import')
->form([
FileUpload::make('data_file')
->acceptedFileTypes(['text/csv'])
->maxFiles(1)
->storeFileNamesIn('file_name')
])
->action(function (array $data): void {
//dd($data);
//try {
Excel::import(new SitesImport, 'test_data/test_sites.csv'); //Manual file name for debugging
//} catch (ValidationException $e) {
// dd($e->failures());
//}

Notification::make()
->title('Imported: ' . $data['file_name'])
->success()
->send();
})
Solution:
So it turns out you were on the right track. I tried giving a bad file name intentionally, and it didn't change the behavior (no exception), which made me realize that the app must be looking for the data in a different place than when I run it from the command line in tinker or a seeder. Sure enough, it's because my test data is in it's own project folder, and moving it to the storage folder fixed it.
Jump to solution
13 Replies
hdaklue
hdaklue16mo ago
It seems a proplem with SitesImport it self. what's the import class code?
awcodes
awcodes16mo ago
What is the result of your dd()? I’m not sure storeFileNamesIn() is going to work like you’re trying it here.
anjama
anjamaOP16mo ago
The first dd()
array:2 [▼ // app/Filament/Resources/SampleResource/Pages/ListSamples.php:32
"data_file" => "khysB1jGuDywaAgy8Fx4oqu0iRZjn7-metadGVzdF9zaXRlcy5jc3Y=-.csv"
"file_name" => "test_sites.csv"
]
array:2 [▼ // app/Filament/Resources/SampleResource/Pages/ListSamples.php:32
"data_file" => "khysB1jGuDywaAgy8Fx4oqu0iRZjn7-metadGVzdF9zaXRlcy5jc3Y=-.csv"
"file_name" => "test_sites.csv"
]
I think it's fine; the notification part is being executed correctly. The second dd() isn't triggered, even when I intentionally try to force an exception. It's like the import line is just being skipped somehow
class SitesImport implements ToModel, WithHeadingRow
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new Site([
"site" => $row['site'],
"lat" => $row['lat'],
"lon" => $row['lon'],
]);
}
}
class SitesImport implements ToModel, WithHeadingRow
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new Site([
"site" => $row['site'],
"lat" => $row['lat'],
"lon" => $row['lon'],
]);
}
}
It works fine outside of the action in Tinker and in a seeder
awcodes
awcodes16mo ago
Ok. The file isn’t going to exist at that filename. So the import won’t be able to find it. Fileuploads are all temporary until after the form is validated an processed. If you want to reference an actual file name other than the hash, you’ll need to use getUploadedFileNameForStorageUsing() And pass the disk and directory to it as a concatenated string.
anjama
anjamaOP16mo ago
To troubleshoot, the way I have it right now, I'm manually specifying a known existing test file and ignoring whatever file the user uploads. So the temporary uploaded file doesn't matter at the moment. Here's a simplified version to illustrate without the file upload part:
Action::make('import')
->action(function (array $data): void {

Excel::import(new SitesImport, 'test_data/test_sites.csv');

Notification::make()
->title('Action ran' )
->success()
->send();
})
Action::make('import')
->action(function (array $data): void {

Excel::import(new SitesImport, 'test_data/test_sites.csv');

Notification::make()
->title('Action ran' )
->success()
->send();
})
So now I have a button that should import that specific data into the database and then create a notification. The data is already in the database, so it should produce an exception. When I press the button, the notification occurs, but the exception doesn't. I can copy/paste the import line into tinker and it does produce the expected exception.
hdaklue
hdaklue16mo ago
in addition add use Importable; to the SiteImport class
awcodes
awcodes16mo ago
What exception are you expecting? When I’ve used the Excel package in the past it didn’t care if data existed or not.
anjama
anjamaOP16mo ago
To force an exception, I'm intentionally trying to add data that already exists. From tinker:
>Excel::import(new SitesImport, 'test_data/test_sites.csv');

Illuminate\Database\QueryException SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'Belmore State Forest' for key 'sites.sites_site_unique' (Connection: mysql, SQL: insert into `sites` (`site`, `lat`, `lon`) values (Belmore State Forest, 29.8, -81.87)).
>Excel::import(new SitesImport, 'test_data/test_sites.csv');

Illuminate\Database\QueryException SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'Belmore State Forest' for key 'sites.sites_site_unique' (Connection: mysql, SQL: insert into `sites` (`site`, `lat`, `lon`) values (Belmore State Forest, 29.8, -81.87)).
hdaklue
hdaklue16mo ago
should throw Reader exception If you're trying to save the data, your class just returning a new Site() you should ->save() it or Site::create([])
anjama
anjamaOP16mo ago
This just makes it so I don't have to use the Facade, no? Adding it doesn't change anything. Neither does changing it to remove use of the Facade If those are needed, then why does it work without those in a seeder and in tinker?
hdaklue
hdaklue16mo ago
tinker will output the class instance without saving them,
anjama
anjamaOP16mo ago
I added a dd() inside the model() method of SitesImport. It didn't trigger, so it seems like it's not getting called for some reason. I just cleared the database, verified the table was empty, ran it in tinker, and now the data is in there. So it is saving them.
Solution
anjama
anjama16mo ago
So it turns out you were on the right track. I tried giving a bad file name intentionally, and it didn't change the behavior (no exception), which made me realize that the app must be looking for the data in a different place than when I run it from the command line in tinker or a seeder. Sure enough, it's because my test data is in it's own project folder, and moving it to the storage folder fixed it.
Want results from more Discord servers?
Add your server