import from csv into multiple related tables

Hi folks, Sorry for asking but I'm really struggling to find any definitive documentation on how to implement this and I'm not even certain that's even possible at least with the ImportAction from Filament. I have a csv with data we've broken down to be distributed into 6 different tables. I understand the relationship model in the Import action is still in its infancy and only supports belongs_to relationships. However I figured even with that there's no reason I couldn't manage to make my objectives work. So what I'm trying to do is this: - create records for tables if they don't already exist and retrieve the id of the record to be recorded as a foreign key - have the import be one single function, not 6 different import actions. I tried stacking ->importer(MyclassImporter::class) in the Resource I want the imort button to be in but if I do that it ignores every importer except for the last one (yet doesn't return an error) Right now I'm trying to define everything under one MyclassImporter.php file and see if I can make relationships work but I'm not having much luck. I tried using dot notation in ImportColumn::make() but although this doesn't throw an error on screen, it doesn't seem to work either. I was trying to see if perhaps the ->resolveRelatedRecord() method for the ImportColumn class would work but I can find no documentation at all on how to use that. The Filament docs have nothing at all on this method. It seems odd to me that there is so little documentation on how to import into multiple tables. Perhaps my search skills have failed me but I would appreciate any guidance you could provide, even if that's just pointing me towards other ways to do this that don't involve Filament. I hope this all makes sense. Cheers
Solution:
@Jean-Loup can you pass in $data? and try this to see if $data is populated. ```php use Illuminate\Support\Facades\Log; ...
Jump to solution
16 Replies
Jean-Loup
Jean-LoupOP3w ago
Yes but I have no idea what else to do beyond that. It's really unclear how to do what I need when you don't refer to a record which already exists Bumping this in case people don't look at this forum on weekends. It would be a great help to find a solution to this today. Thanks
toeknee
toeknee3w ago
If you set the relationship, then the column can resolve etc as per the documents on that? So you could resolve the Author column by email or username within the database. We would need more details of what you are trying to achieve for anything else, with say the data you are trying to import.
Jean-Loup
Jean-LoupOP3w ago
I'm not using authors but why not it works as an example. I can't give you the exact data I'm working with as it's confidential but for the sake of moving forward say I have a CSV of books and authors. Both the author and book tables are empty to start with. I want for each line it reads to search if an author already exists and add one if not, then retrieve the author id from there to add it to the book table as a foreign key. That's a 2-table example but of course I'll need to expand that to my 6 tables. Does that make sense?
toeknee
toeknee3w ago
We know your not using Author but the Author is an example of the context. So as per the doc's adjust:
->relationship(resolveUsing: function (string $state): ?Author {
return Author::query()
->where('email', $state)
->orWhere('username', $state)
->first();
})
->relationship(resolveUsing: function (string $state): ?Author {
return Author::query()
->where('email', $state)
->orWhere('username', $state)
->first();
})
to:
->relationship(resolveUsing: function (string $state): ?Author {
return Author::query()
->where('email', $state)
->orWhere('username', $state)
->firstOrCreate([
'email' => $state,
'username' => $state,
]);
})
->relationship(resolveUsing: function (string $state): ?Author {
return Author::query()
->where('email', $state)
->orWhere('username', $state)
->firstOrCreate([
'email' => $state,
'username' => $state,
]);
})
This would in Author context find and return it to be mapped as the relationship, else create it then map it.
Jean-Loup
Jean-LoupOP3w ago
Right thanks I didn't know you could append firstOrCreate() in that way. I'll try it and get back to you Ok so the upload form always wants to map author to one of the columns of the csv which means $state always has the same value. How do I make sure this $state contains multiple columns which can then be mapped to a single table columns?
toeknee
toeknee3w ago
Seperate the values in the column with say: ; and explode state in the find record to get the multiple values?
Jean-Loup
Jean-LoupOP3w ago
But the docs say you can pass multiple columns to resolveUsing. It's just unclear whether this also works when passing a function
toeknee
toeknee3w ago
That's not what it's saying, it's saying Database Columns. So 'author' column in the CSV can be used to look in email and username columns within the database.
Jean-Loup
Jean-LoupOP3w ago
Yeah that's not very clear then. So there's no way to pull more than one column in one statement then, not without modifying the structure of the imported file
toeknee
toeknee3w ago
At present not that I know off, I didn't write the routine and haven't dug down on the codebase. Might be able to pass $get or $data in... but haven't trie.d
Jean-Loup
Jean-LoupOP3w ago
Any tips on how I can retrieve either of those? Everything I try seems to end up in the wrong scope :/
toeknee
toeknee3w ago
I'm checking with Dan as I don't think it's currently possible
Jean-Loup
Jean-LoupOP3w ago
Thanks I appreciate that
Solution
toeknee
toeknee3w ago
@Jean-Loup can you pass in $data? and try this to see if $data is populated.
use Illuminate\Support\Facades\Log;

->relationship(resolveUsing: function (string $state, $data): ?Author {
Log::info('Data:', ['data' => $data]);

return Author::query()
->where('email', $state)
->orWhere('username', $state)
->firstOrCreate([
'email' => $state,
'username' => $state,
]);
})
use Illuminate\Support\Facades\Log;

->relationship(resolveUsing: function (string $state, $data): ?Author {
Log::info('Data:', ['data' => $data]);

return Author::query()
->where('email', $state)
->orWhere('username', $state)
->firstOrCreate([
'email' => $state,
'username' => $state,
]);
})
Then check the laravel log?
Jean-Loup
Jean-LoupOP3w ago
This worked a treat thank you. I still have some cleaning up to do on my data but now I have something I can use to move forward. Very grateful for your help

Did you find this page helpful?