Upload and Parse CSV with Laravel MediaLibrary and SpreadsheetReader

Quick example of a code I had to write recently. Task is simple - upload CSV and parse it. Also save that file and the record, which user uploaded it. Let's take a look.

Here's the code of the Controller's method, I will explain it bit by bit below:

public function importProcess(UploadImportModelRequest $request)
{
    $originalFile   = $request->file('import_file');
    $import = Import::create([
        'filename' => $originalFile->getClientOriginalName(),
        'user_id' => auth()->id(),
    ]);

    $file = $import->addMediaFromRequest('import_file')
        ->toMediaCollection('imports');

    $filename = storage_path('app/' . $file->id . '/' . $file->file_name);
    $reader = new \SpreadsheetReader($filename);
    foreach ($reader as $row) {
        // Parsing the rows...
    }
}

Explanation 1. Validation FormRequest

See the class UploadImportModelRequest in the parameters? It just helps us to validate that file is present and it is, in fact, CSV or TXT.

app/Http/Requests/UploadImportModelRequest.php:

class UploadImportModelRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'import_file' => [
                'required',
                'file',
                'mimes:csv,txt'
            ],
        ];
    }
}

Read more about file validation rules in this article.


Explanation 2. Upload File with Laravel MediaLibrary

This package is probably the most popular for file uploads in Laravel, and here's the reason why - you can do a lot of things in a few lines of code.

But first, we need to store the record of import actually happened, and get Eloquent model object for it:

$originalFile   = $request->file('import_file');
$import = Import::create([
    'filename' => $originalFile->getClientOriginalName(),
    'user_id' => auth()->id(),
]);

So we store the original filename, whatever it is, like "dummy import test.csv" or something like that. Soon I will show you why that "original" is important.

The result of that Eloquent query is $import object, and that's where Laravel MediaLibrary comes handy - in one line of code we can store the file into a folder, and also assign that file to that $import object:

$file = $import->addMediaFromRequest('import_file')
    ->toMediaCollection('imports');

The result of this is:

  • New DB record stored in "media" table with filename and relationship to that $import object;
  • A folder created in storage/app folder, with ID of that "media" record;
  • Inside of that new folder - upload file is stored;
  • That "media" record object is returned into $file.

Explanation 3. Getting REAL filename and parsing CSV

Important thing is that Laravel MediaLibrary actually renames the file to make it "sluggable", so the actual filename is different from the original one. See difference in the filename and record in "media" DB table:

That's why we need to read the CSV file with its new filename, which is stored inside of that $file object.

$filename = storage_path('app/' . $file->id . '/' . $file->file_name);
$reader = new \SpreadsheetReader($filename);
foreach ($reader as $row) {
    // Parsing the rows...
}

As you can see, we're referring to the file as storage/[media.id]/[media.file_name] now.

In this example, I won't show CSV parsing in details, as it is very individual, but I recommend to use a Spreadsheet Reader package - it's quite old, but for some reason works much faster than Laravel Excel or others.

No comments or questions yet...

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 57 courses (1055 lessons, total 46 h 42 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials