Laravel-excel: Can't Excel::import() after HeadingRowImport

Created on 17 Oct 2018  路  8Comments  路  Source: Maatwebsite/Laravel-Excel

When using HeadingRowImport for file validation, as suggested here it's impossible to run Excel::import() with the same uploaded file, since it delete it.

documentation

Most helpful comment

Awesome, looks good @zanozik

All 8 comments

Thanks for submitting the ticket. Unfortunately the information you provided is incomplete. We need to know which version you use and how to reproduce it. Please include code examples. Before we can pick it up, please check (https://github.com/Maatwebsite/Laravel-Excel/blob/3.0/.github/ISSUE_TEMPLATE.md) and add the missing information. To make processing of this ticket a lot easier, please make sure to check (https://laravel-excel.maatwebsite.nl/docs/3.0/getting-started/contributing) and double-check if you have filled in the issue template correctly. This will allow us to pick up your ticket more efficiently. Issues that follow the guidelines correctly will get priority over other issues.

Please provide more information according to the issue template.

The following should work:

$headings = (new HeadingRowImport)->toArray('users.xlsx');

/**
* Perform whatever validation on the headings here
*/

Excel::import(new UsersImport, 'users.xlsx');

return redirect('/')->with('success', 'All good!');

Not work when you let user upload the document, and you want validate $request->file, because the file once was read by HeadingRowImport is remove from temporary space.

You need to store the file and then validate.

In this situation I'd suggest storing the file to a disk, and using that file instead of using the uploaded file twice.

Thank you for answers! Since moving a file to storage was extremely inconvenient for the project, I have designed the workflow differently by subscribing with Reader::listen globally (validation by header used project-wide).
Could share my code if anyone interested.

@zanozik sounds like a nice solution as well :) Feel free to share! Can definitely help someone!

So this is the most cleanest project-wide way I could come up with:

Create regular import file:
````php
namespace App\Imports;

use App\Models\Transports\GasStations\GasStation;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class GasStationImport implements ToModel, WithHeadingRow
{
public $model = GasStation::class; // Only needed for globalization purpose

// Excel file header
public $header = [
'name', 'country', 'city','address', 'postal', 'zone', 'latitude', 'longitude'
];

public $verifyHeader = true; // Header verification toggle

public $truncate = true; // We want to truncate table before the import

/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
    return new $this->model($row); // We have matching table fields, so we can just do that
    // return new GasStation($row); // If you don't need globalization
}

}
And in `app\Providers\AppServiceProvider.php`: php
namespace App\Providers;

use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Imports\HeadingRowExtractor;
use Maatwebsite\ExcelReader;

class AppServiceProvider extends ServiceProvider
{

public function register()
{
    Reader::listen(BeforeImport::class, function (BeforeImport $event) {

        $concernable = $event->getConcernable();

        if ($concernable->verifyHeader) {

            //Extracting and "truncating" header from Excel's active worksheet (assuming import is only single worksheet)
            $header = array_filter(HeadingRowExtractor::extract($event->getDelegate()->getDelegate()->getActiveSheet(), $concernable));

           //Checking if headers match and throwing ValidationException otherwise
            throw_unless($header === $concernable->header, ValidationException::withMessages(['message' => trans('validation.unknown_file_template')]));
        }

        //This is where GasStationImport's $truncate and $model come into play. You can put your logic here. 
        if($concernable->truncate) {
            $concernable->model::truncate();
        }
    });
}

}

In your controller, a method could look like this: php
public function import(Request $request)
{
$this->validate($request, [
'file' => 'required|file|max:1024|mimes:xls,xlsx'
]);

    \Excel::import(new GasStationImport(), $request->file('file'));

    return response()->json(['message' => trans('app.import_successful')]);
}

````

Typos edited

Awesome, looks good @zanozik

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kurianic picture kurianic  路  3Comments

disto picture disto  路  3Comments

lucatamtam picture lucatamtam  路  3Comments

daraghoshea picture daraghoshea  路  3Comments

contifico picture contifico  路  3Comments