Как загрузить файл CSV в фоновом режиме с помощью PHP (Laravel 5.8) - PullRequest
3 голосов
/ 10 июня 2019

Я хочу создать функциональность в Laravel 5.8, которая поможет мне загрузить CSV-файл и импортировать данные в базу данных, но все это должно происходить в фоновом режиме (на стороне сервера), и после его завершения отправьте электронное письмо на адрес вошел в систему пользователя. Я хочу получить лучшее понимание, прежде чем начать процесс, если я сделаю это с помощью Scheduler, или найдется лучший способ или библиотека, которая поможет мне реализовать эту функцию.

Жду ваших мыслей :))

Спасибо.

Ответы [ 3 ]

2 голосов
/ 10 июня 2019

Начиная с нуля:

Создайте таблицу invoices и соответствующую модель:

php artisan make: модель счета -m

Ваша модель должна выглядеть так:

<?php

namespace App;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class Invoice extends Model
{
    protected $table = 'invoices';
    protected $fillable = [
        'user_id',
        'processed',
        'path'
    ];

    public function scopeNotProcessed(Builder $query)
    {
        return $this->where('processed', '=', false);
    }
}

А вот таблица invoices:

public function up()
{
    Schema::create('uploads', function (Blueprint $table) {
        $table->increments('id');
        $table->string('path')->nullable(false);
        $table->boolean('processed')->default(false)->nullable(false);
        $table->timestamps();
    });
}

После того, как все это будет сделано, сделайте следующее:

Создайте репозиторий, который будет загружать ваш CSV-файл. Этот файл должен быть помещен в app/Repositories/CSVRepository

<?php

namespace App\Repositories;

use Illuminate\Support\Facades\Storage;
use App\Invoice;

class CSVRepository {

    /**
     * CSVRepository constructor.
     */
    public function __construct()
    {
        //
    }

    /**
     * @param $file
     * @param $extension
     * @return mixed
     */
    public function uploadCSV($file, $extension){
        return $this->upload($file, $extension);
    }

    /**
     * @param $file
     * @param $extension
     * @return mixed 
     */
    private function upload($file, $extension){
        $path = Storage::putFileAs("myFileName", $file, uniqid().".".$extension);
        $uploadedFile = Invoice::create([
            'path' => $path,
            'processed' => false,
        ]);

        return $uploadedFile;
    }
}

Теперь создайте свой контроллер, который будет загружать файл на сервер, используя CSVRepository: Функция загрузки должна выглядеть следующим образом:

public function upload(CSVRepository $CSVRepository)
{
    try{
        $file = Input::file('file');
        $extension = strtolower($file->getClientOriginalExtension());
        if ($extension !== 'csv'){
            $errors['file'] = 'This is not a .csv file!';
            return redirect()->back()->withInput()->withErrors($errors);
        }
        $CSVRepository->uploadCSV($file, $extension); 
        $message = array(
            'type' => 'success',
            'text' => 'Your file has been uploaded! You will receive an email when processing is complete!',
            'title' => 'Success',
        );
        session()->flash('message', $message);
        return redirect('route-to-redirect');
    }catch (\Exception $exception){
        return abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error');
    }
}

Теперь вам нужна работа, которая обрабатывает файл для вас:

Начните создавать команду с помощью команды ремесленника:

php artisan make: команда ProcessCSVCommand

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Invoice;

use Illuminate\Support\Facades\Storage;

class ProcessCSVCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'csv:process';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Process an uploaded CSV file';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        try{
            //Retrieve only no processed files:
            $invoices = Upload::notProcessed()->get();
            if (count($files) < 1){
                $this->info('No files found');
                return;
            }
            //Process the files:
            $invoices->map(function($invoice){ 
                $file = fopen("storage/app/".$invoice->path, "r");
                while (!feof($file)){
                    $line = fgets($file); 
                    //Here you have a loop to each line of the file, and can do whatever you need with this line:
                    if(strlen($line) > 0){ //If the line is not empty:
                        // Add your logic here:
                    }
                    // Don't forgot to change your `processed` flag to true:
                    $invoice->processed = true;
                    $invoice->save(); 
                } 
            });
        }catch (\Exception $exception){
            $this->error("Something went wrong");
            return $exception->getMessage();
        }
    }
}

Теперь откройте файл app/Console/Commands/Kernel.php:

Зарегистрируйте новую команду в массиве $commands:

$commands = [
    Commands\ProcessCSVCommand::class,
];

Запланируйте задание, которое будет выполняться на вашем сервере, проверяя файлы, которые нужно обработать, и, если это так, обрабатывайте их:

В том же файле, теперь с функцией schedule:

protected function schedule(Schedule $schedule)
{
     $schedule->command('csv:process')
              ->everyFiveMinutes();
}

Надеюсь, это поможет.

1 голос
/ 10 июня 2019

Очередь - это путь для такой работы. По сути, загрузка этого файла должна происходить в этом одном запросе, но после этого вы можете создать очередь (и), которая будет преобразовывать CSV в записи в базе данных.

0 голосов
/ 10 июня 2019

Я думаю, что вы, возможно, захотите рассмотреть использование очередей и прослушивание события, обработанного заданием, как упомянуто здесь https://laravel.com/docs/5.8/queues#job-events, откуда вы можете затем отправить свою почту

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...