定制 jhonoryza/laravel-import-tables 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

jhonoryza/laravel-import-tables

最新稳定版本:1.0.2

Composer 安装命令:

composer require jhonoryza/laravel-import-tables

包简介

laravel package handling import tables

README 文档

README

Latest Stable Version Total Downloads Latest Unstable Version License

This package provide ability to track import progress and history

Requirement

Getting Started

composer require jhonoryza/laravel-import-tables

run migration to create imports table

php artisan migrate

How it works

when import is start all the progress data will be saved to redis, after import event or failed event triggered, the progress data will be flushed to the database imports table.

Change redis connection

publish the configuration

php artisan vendor:publish --tag import-tables

this will copy default config to config/import-tables.php

you can change redis connection to be used here

Usage Example

create controller class ImportController

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Maatwebsite\Excel\Facades\Excel;
use App\Imports\UserImport;
use Jhonoryza\LaravelImportTables\Repositories\ImportRepository;
use Jhonoryza\LaravelImportTables\Services\ImportProgress;

class ImportController extends Controller
{
    /**
     * get all import data
     */
    public function index(Request $request, ImportRepository $repo)
    {
        $imports = $repo->getList(
            status: $request->get('status'),
            module: $request->get('module'),
            limit: 50
        );

        return response()->json($imports);
    }

    /**
     * get specific import data
     */
    public function show($id, ImportRepository $repo)
    {
        $import = $repo->getById($id);

        return response()->json($import);
    }

    /**
     * import function
     */
    public function store(Request $request)
    {
        $request->validate([
            'file'   => 'required|file|mimes:xlsx,csv',
            'module' => 'required|string',
        ]);

        $file = $request->file('file');

        $this->validateDuplicate($file);

        $identifier = 'user';
        $this->validateProcessingImport($identifier);

        ImportProgress::make($identifier)
            ->pending('user', $file->getClientOriginalName());

        $import = new UserImport($identifier);
        $import->queue($request->file('file'));

        return response()->json([
            'message' => 'processing user import',
            'import_id' => $repo->getModel()->id,
        ]);
    }

    private function validateProcessingImport($identifier): void
    {
        $isProcessing = ImportProgress::make($identifier)
            ->isProcessing();

        if ($isProcessing) {
            session()->flash('failed', "please try again, there is ongoing process user import.");
            throw ValidationException::withMessages([]);
        }
    }

    private function validateDuplicate($file): void
    {
        $data = Excel::toArray([], $file)[0]; // First Sheet
        $emails = collect($data)
            ->skip(1) // skip header
            ->pluck(0) // first column
            ->filter();

        $duplicates = $emails
            ->values()
            ->duplicates();

        if ($duplicates->isNotEmpty()) {
            $message = 'Duplicate mails in Excel file: ' . $duplicates->join(', ');
            session()->flash('failed', $message);
            throw ValidationException::withMessages([]);
        }
        $emails = $emails->all();

        $duplicates = DB::table('users')
            ->select('email')
            ->whereNull('deleted_at')
            ->whereIn('email', $emails)
            ->get();

        if ($duplicates->isNotEmpty()) {
            $duplicateCount = $duplicates->count();
            $displayLimit = 5;

            if ($duplicateCount > $displayLimit) {
                $codesToDisplay = $duplicates->take($displayLimit)->implode('email', ', ');
                $message = "There is {$duplicateCount} duplicate mails. some example: {$codesToDisplay}, ...";
            } else {
                $codesToDisplay = $duplicates->implode('email', ', ');
                $message = "Duplicate mails founded: {$codesToDisplay}";
            }
            session()->flash('failed', $message);
            throw ValidationException::withMessages([]);
        }
    }
}

create import class UserImport

<?php

namespace App\Imports;

use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\SkipsFailures;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\ShouldQueue;
use Maatwebsite\Excel\Events\AfterChunk;
use Maatwebsite\Excel\Events\AfterImport;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Validators\Failure;
use App\Models\User;
use Jhonoryza\LaravelImportTables\Services\ImportProgress;

class UserImport implements ToModel, WithHeadingRow, WithChunkReading, WithBatchInserts, WithEvents, ShouldQueue, SkipsEmptyRows, WithValidation, SkipsOnFailure
{
    use SkipsFailures;
    use Importable;

    private string $identifier;

    public function __construct(string $identifier)
    {
        $this->identifier = $identifier;
    }

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

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

    public function rules(): array
    {
        return [
            '*.name' => [
                'required',
            ],
            '*.email' => [
                'required',
            ],
        ];
    }

    public function model(array $rows)
    {
        return User::create([
            'name'  => $row['name'],
            'email' => $row['email'],
        ]);
    }

    public function registerEvents(): array
    {
        return [
            BeforeImport::class => function () {
                ImportProgress::make($this->identifier)
                    ->processing();
            },
            AfterImport::class => function () {
                ImportProgress::make($this->identifier)
                    ->done();
            },
        ];
    }

    public function getFailures()
    {
        return $this->failures();
    }

    public function onFailure(Failure ...$failures)
    {
        $progress = ImportProgress::make($this->identifier);

        foreach ($this->failures as $failure) {
            $err = 'row: ' . $failure->row() . ' err: ' . collect($failure->errors())->implode(',');
            $progress
                ->pushFailMessage($err)
                ->incrementFail();
        }

        $this->failures = array_merge($this->failures, $failures);
}

    public function failed(\Throwable $e)
    {
        ImportProgress::make($this->identifier)
            ->pushFailMessage($e->getMessage())
            ->failed();
    }
}

another sample using ToCollection approach

public function collection(Collection $collection)
{
    $rows = $collection->map(fn($row) => [
        'is_receive_repeatedly' => 1,
        'voucher_id' => $this->voucherId,
        'code' => $row['code'],
        'allocation' => 1,
        'created_at' => now(),
        'updated_at' => now(),
    ])->toArray();

    try{
        DB::beginTransaction();

        VoucherCode::insert($rows);

        DB::commit();

        ImportProgress::make($this->identifier)
            ->incrementOk(count($rows))
            ->pushOkMessage("Inserted " . count($rows) . " rows");

    } catch (Throwable $th) {
        DB::rollBack();

        ImportProgress::make($this->identifier)
            ->incrementFail($collection->count())
            ->pushFailMessage("Error: " . $th->getMessage());
    }
}

the rest implementation is the same

Security

If you've found a bug regarding security, please mail jardik.oryza@gmail.com instead of using the issue tracker.

License

The MIT License (MIT). Please see License File for more information.

统计信息

  • 总下载量: 1
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-09-02