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

时间:2019-06-09 22:44:51

标签: php mysql database laravel laravel-5

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

期待听到您的想法:)

谢谢。

3 个答案:

答案 0 :(得分:2)

从头开始:

创建一个invoices表和相应的模型:

  

php artisan make:model发票-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');
    }
}

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

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

  

php artisan make:command 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 :(得分:1)

队列是进行此类工作的方式。上传文件本质上需要在一个请求中完成,但是除此之外,您可以创建一个队列,该队列将减少将CSV转换为数据库中的记录的速度。

答案 2 :(得分:0)

我认为您可能要考虑使用“队列”并监听https://laravel.com/docs/5.8/queues#job-events处提到的作业处理事件,然后从那里发送邮件