如何使用 PHP 在后台进程中上传 CSV 文件 (Laravel 5.8)

Lak*_*hya 3 php mysql database laravel laravel-5

我想在 Laravel 5.8 中构建一个功能,可以帮助我上传 CSV 文件并将数据导入数据库,但这一切都应该在后台(服务器端)进程中,完成后向登录用户发送电子邮件。我想在开始这个过程之前更好地理解我是否应该在以下帮助下完成此操作Scheduler,或者是否有更好的方法或库可以帮助我实现此功能。

期待听到您的想法:)

谢谢。

Mat*_*ges 6

从头开始:

创建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);
    }
}

Run Code Online (Sandbox Code Playgroud)

这是invoices表格:

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();
    });
}
Run Code Online (Sandbox Code Playgroud)

完成这些事情后,请执行以下操作:

创建一个存储库,它将上传您的 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,创建控制器,它将使用以下命令将文件上传到服务器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');
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您需要一份工作来为您处理文件:

开始使用 artisan 命令创建命令:

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 = 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,打开您的app/Console/Kernel.php文件:

在数组中注册您的新命令$commands

$commands = [
    Commands\ProcessCSVCommand::class,
];
Run Code Online (Sandbox Code Playgroud)

安排一个在您的服务器上运行的作业,检查要处理的文件,如果是,则处理它们:

在同一个文件中,现在在函数中schedule

protected function schedule(Schedule $schedule)
{
     $schedule->command('csv:process')
              ->everyFiveMinutes();
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你。