Laravel-excel: [QUESTION] after import event

Created on 7 Dec 2018  ·  24Comments  ·  Source: Maatwebsite/Laravel-Excel

Prerequisites

Versions

  • PHP version: 7.2
  • Laravel version: 5.7
  • Package version: 3.1

Description

I have some trouble getting the after import event to work. The event never fires. :(
The after sheet works fine, what am I doing wrong?

i have tried both the register events and the auto register events.

My code

namespace App\Imports;

use App\Order;
use App\Order\Address;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Events\AfterImport;
use Maatwebsite\Excel\Events\BeforeImport;

class OrderAddressImport implements
    WithHeadingRow,
    ToModel,
    WithBatchInserts,
    WithChunkReading,
    WithCustomCsvSettings,
    ShouldQueue,
    WithEvents
{
    use Importable, RegistersEventListeners;

    protected $order;

    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    /**
     * @param array $row
     * @return Address
     */
    public function model(array $row)
    {
        $data = ['order_id' => $this->order->id];
        $data = array_merge($data, $row);

        return new Address($data);
    }


    public function batchSize() : int
    {
        return 1000;
    }

    public function chunkSize() : int
    {
        return 5000;
    }

    /**
     * @return array
     */
    public function getCsvSettings(): array
    {
        return [
            'delimiter' => ';',
            'enclosure' => '',
            'input_encoding' => 'UTF-8'
        ];
    }

    public static function afterImport(AfterImport $event)
    {
       dd($event);
    }
}
bug

Most helpful comment

Next release (currently 3.1-dev) will have support for Before/AfterImport events for chunk reading. It will also add ImportFailed event that gets raised when any of the chunk jobs fail. (https://twitter.com/patrickbrouwers/status/1114166252711415808)

Feel free to test it on the 3.1 branch and let me know if it works like excepted.

All 24 comments

I have the same issue. It seems the AfterImport event is never fired if you're implementing the WithChunkReading contract.

This appears to also be true for the BeforeImport event

I had a quick look at the code and can not see any code that will fire this event at all in the ChunkReader class.

And when i think about it there is no nice solution for this. Maybe one solution could be to ad a single job to the chain for it to raise the afterImport method?

Do we have any answers to this topic? :)

Yes, we've identified this as a bug. We'll see if we can come up with a solution for it in a future version.

@GlennM Speaking with this, I would like to see if there is a way to also implement a BeforeChunk and AfterChunk event as well, to be able to update a front end gui of progress as it is worked... Things to consider with this, should be total count + total chunks + current chunk (just for thoughts), most of my files are done through the GUI but are fairly large, so being able to give them some kind of "it's in progress" is better than an indeterminate progress bar

BeforeChunk and AfterChunk sound possible.

The BeforeImport/AfterImport are more tricky. Adding them as 2 extra jobs to the chain, will have performance impact, as it will 2x times re-open the file. The best option would be able to only execute the beforeimport on the first job and the afterimport on the last job. I'll see if that's possible.

+1 to adding BeforeImport/AfterImport events to chunk jobs. I was about to submit a proposal to add these as two jobs to the chain, but it sounds like you're already on it! Your suggestion of implementing the events on the first and last job sounds best too if possible.

AfterImport does not work with ShouldQueue and WithChunkReading.
In addition, they are required for queues, so an event at the end of running a queue is not implemented.

with the suggestion of documentation:

$ import-> queue ('users.xlsx') -> chain ([
new NotifyUserOfCompletedImport (request () -> user ()),
]);

Each of the queue items is fired the: NotifyUserOfCompletedImport

Alguma sugestão?

I've run into the same issue. Solved it by creating a Job implementing ShouldQueue, then running the Import from it and performing the necessary actions (that otherwise would be in afterImport event) after the Import is finished. The Import has configured batch inserts and chunk reading and is executed synchronously in the Job.

One benefit of the above is that I can easily control which Queue worker is executing the job.

and another (very important) benefit is that I can import XLS files with the queued job. Something that is not possible if using the standard approach with implementing ShouldQueue in the Import class itself.

ihave the same question。。。how can i do ....please

@zxl2006001 With the updated documentation from @patrickbrouwers i solved my issue with this logic.

(new UsersImport)->queue('users.xlsx')->chain([
    new NotifyUserOfCompletedImport(request()->user()),
]); 

see here: https://docs.laravel-excel.com/3.1/imports/queued.html#appending-jobs

There are actually two more consequences of current design:

  1. Looking at Reader classes read method it's not obvious why beforeImport is fired only inside beforeReading instead of being fired synchronously before ChunkReader reads are invoked.

  2. In chunked scenario you can chain a job to do any notification stuff but since "currentFile" property is protected you cannot do proper cleanup of temporary file and it's not done automatically - a job chained after all ReadChunk's would be very helpful both with afterImport and with temp cleanup.

Do we have any workarounds for handling failed imports? The only method I can currently think of is using laravels global job error event.

Problem with that is I have no control over the aatwebsiteExcel\Jobs\ReadChunk process. This means I can't pass the global event the data I need about the failed job.

How can we handle errors when using chunkSize?

Next release (currently 3.1-dev) will have support for Before/AfterImport events for chunk reading. It will also add ImportFailed event that gets raised when any of the chunk jobs fail. (https://twitter.com/patrickbrouwers/status/1114166252711415808)

Feel free to test it on the 3.1 branch and let me know if it works like excepted.

If I use database queue driver for imports and implement WithChunkReading on my import class it seams to trigger AfterImport event multiple times. Is that expected behavior?

I'm experiencing AfterImport being triggered twice after every successful import, with database queue driver and version 3.1.

Im experiencing AfterImport being triggered indefinitely after running a successful import also with database queue driver and version 3.1

If I use redis queue driver for imports and implement WithChunkReading on my import class it seams to trigger AfterImport event multiple times. Is that expected behavior?

Here is error log:

local.ERROR: unlink(/Users/sineld/Code/project/public/uploads/tmp/laravel-excel-qfK6O5aCHxhFXioVayQbLQag5UnFKyxB.xlsx): No such file or directory {"exception":"[object] (ErrorException(code: 0):

Same her AfterImport is called twice.

I'm also running into AfterImport listeners being called twice. After debugging with xdebug I found that the listeners are registered in two places:

Fixed for next release

Was this page helpful?
0 / 5 - 0 ratings