3
votes

Comment télécharger un fichier CSV en arrière-plan avec PHP (Laravel 5.8)

Je souhaite créer une fonctionnalité dans Laravel 5.8 qui puisse m'aider à télécharger un fichier CSV et à importer les données dans la base de données, mais tout devrait être en arrière-plan (côté serveur) et une fois terminé, envoyez un e-mail au utilisateur connecté. Je veux avoir une meilleure compréhension avant de commencer le processus si je le fais avec l'aide de Scheduler ou il y aurait un meilleur moyen ou une meilleure bibliothèque qui peut m'aider à réaliser cette fonctionnalité.

Au plaisir d'entendre vos impressions :)

Merci.


0 commentaires

3 Réponses :


1
votes

Les files d'attente sont la voie à suivre pour ce genre de travail. Le téléchargement du fichier doit essentiellement se produire dans cette demande, mais au-delà de cela, vous pouvez créer une ou plusieurs files d'attente qui seront supprimées lors de la conversion du CSV en enregistrements dans la base de données.


0 commentaires

2
votes

En partant de zéro:

Créez un tableau factures et le modèle correspondant:

php artisan make: model Invoice -m

Votre modèle devrait ressembler à ceci:

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

Et voici le tableau des factures :

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

Après avoir fait ces choses, procédez comme suit:

Créez un dépôt, ce qui va télécharger votre fichier csv. Ce fichier doit être placé à app/Repositories/CSVRepository:

<?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 = Invoice::notProcessed()->get();
            if (count($invoices) < 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();
        }
    }
}

Maintenant, créez votre contrôleur, qui téléchargera le fichier sur le serveur en utilisant le CSVRepository code>: La fonction de téléchargement devrait ressembler à celle-ci:

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');
    }
}

Maintenant, vous avez besoin d'un travail qui traite le fichier pour vous:

Commencez à créer une commande la commande artisan:

php artisan make: commande ProcessCSVCommand

<?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;
    }
}

Maintenant, ouvrez votre fichier app / Console / Kernel.php :

Enregistrez votre nouvelle commande dans le $ commands array:

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

Planifier une tâche qui s'exécute sur votre serveur, en vérifiant les fichiers à traiter et, si oui, en les traitant: p >

Dans le même fichier, maintenant à la fonction planning :

<?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);
    }
}

J'espère que cela aide.


0 commentaires

0
votes

Je pense que vous voudrez peut-être envisager d'utiliser les files d'attente et d'écouter l'événement traité par le travail comme mentionné ici https://laravel.com/docs/5.8/queues#job-events d'où vous pouvez ensuite envoyer vos e-mails


0 commentaires